Rを使ったプログラミング演習

前回から使いはじめたRというソフトウェア。コマンドを入力するのはちょと難しいけど、エクセルみたいにマウスを使って面倒な操作をしなくても、一瞬にして統計解析をやってくれるし、グラフも簡単に描けてしまう優れもの。これなら、レポートや卒論のために、何度も解析をやりなおして、グラフを描き直すという作業も面倒ではないだろう。  初めて使ったソフトなのに、受講生の皆さんは、すでにRの操作には慣れてきているし(全員、課題ができていた)、興味も感じているよう。そこで、今回はRを使ったプログラミングに挑戦する。

第9回授業の獲得目標: [worried]

  • 1. プログラミングとは何かを理解する
  • 2. プログラミングにおける繰り返しと代入と条件分岐を習得する
  • 3. ユーザー定義関数を理解する
  • 4. Rで基本的なプログラムを作成し、実行できるようになる

演習:今日の正規表現: データ整形

以下、これまでに習った正規表現を使って、データを整形してエクセルで集計可能な形にしてください。今回は後方参照は必要ありません。

前回課題2

   * 1:30         * 2:28
   * 1:30         * 2:18
   * 1:34         * 2:30
   * 1:31         * 2:28
   * 1:18         * 2:31
   * 1:34         * 2:18
   * 1:18         * 2:30
   * 1:34         * 2:30
   * 1:31         * 2:28
   * 1:34         * 2:30
   * 1:34         * 2:16
   * 1:28         * 2:16
   * 1:30         * 2:28
   * 1:30         * 2:18
   * 1:30         * 2:19
   * 1:18         * 2:11
   * 1:31         * 2:28
   * 1:28         * 2:30
   * 1:30         * 2:31
   * 1:18         * 2:30
   * 1:28         * 2:34
   * 1:30         * 2:31
   * 1:22         * 2:31
   * 1:28         * 2:32
   * 1: 28         * 2: 30
   * 1:34         * 2:18
   * 1:34         * 2:28
   * 1:30         * 2:28
   * 1:23         * 2:34
   * 1:30         * 2:18
   * 1:18         * 2:17
   * 1:30番の葉緑体         * 2:15番の葉緑体
   * 1:28         * 2:24
   * 1:30         * 2:31

前回課題で皆さんにやってもらった評価を集計してみよう。

手順

  1. まずは余分な文字を消して、タブ区切りにする
    • 全部をコピーして、K2Editorにペースト
    • 余分な文字列を一括置換で削除
          * 1:
          * 2:
          漢字
          行頭の半角空白など
  2. Excelにペーストし、全角文字を半角文字に変換する ASC()という関数を使用すればできる
  3. 並べ替えて集計。1番、2番で傾斜配点して合計を集計しても良い

前回課題3 : Ozawa-kenによるタイピング技能測定結果

C     B     B     B     C     A
B     B     A+++     B     S     C
A+     B     G     B     B     C
B     C     C     A     C     C
B     B     C     G     B     A+++
B     C     C     C

集計の手順

  1. まずは空白(あるいはタブ)で改行して、1列のデータにする
  2. 全てを選択してエクセルにコピー
  3. 並び替えてデータごとに個数を集計

なお、タイピングに苦手意識が無くなれば、コンピュータへの苦手意識も減少するので、今後もぜひ練習をつづけるように。
最後の講義の前にもう一度測定するが、上達の程度によっては加点対象になるかも。

仮説検定:補足

前回アンケートで、仮説検定について「帰無仮説や有意水準などが分からない。」、「Rの操作は分かったけど、その意味が分からない」という意見があります。でも、私は、今の段階では、

全員がRを使って仮説検定の操作を行うことができただけで十分!

と考えています。生物学では収集したデータをもとに何らかの判断を下す場合、ほとんどの場合仮説検定が必要になります。これは別に系統学や生態学に限ったことではありません。最新号のNatureに載っている染色体不安定性を示すマウスの腫瘍に関する論文でもt検定が使われています。

  • http://www.nature.com/nature/journal/v447/n7147/abs/nature05886_ja.html

    議論の性質やデータの性質によって仮説検定の方法は異なりますが、今回皆さんが体験した考え方と解析方法は、いずれの仮説検定にも応用できるはずです。興味を持ったらいろんな教科書を読んだり、Rのマニュアルを読んでみてください。中澤さんの書かれた、Rを使った統計解析の解説PDF(http://phi.med.gunma-u.ac.jp/statlib/stat.pdf)は、無料ですし、Rで操作を試しながら読むことができます。

プログラミングって何? [smile]

 プログラミングっていったい何をすることだろうか?IT用語辞典で調べてみると、、、

  載っていない

 唯一近いところでは、「プログラミング言語」というのがある。IT用語辞典の説明文からプログラミングに関わるところを抜き出して、「プログラミング」の説明文を作ってみると、

  • プログラミング: 人間に理解できるように英語などを元に作られたプログラミング言語を用いて、コンピュータに実行させる命令を作ること。できた命令はソースコード、プログラム、スクリプトなどの名前で呼ばれる。命令文をコンピュータに実行させるためには、コンピュータが理解可能な機械語の羅列(オブジェクトコード)に翻訳する必要がある。プログラミング言語によっては、コンパイルという翻訳作業を別にしなければならないコンパイラ型言語と、リアルタイムに翻訳作業をしてコンピュータに命令を渡すインタプリタ型言語がある。

 つまり、プログラミングとは、簡単に言うと、「言葉を使ってコンピュータが理解できる命令を作ること」。  今日使うRは統計解析ソフトでもあるけれど、インタプリタ型のプログラミング言語でもある。

コンピュータにどんな命令ができるのか? or どんな命令がしたいか?

 「Wordを立ち上げて文章を作成し、印刷する」とか、「Excelで家計簿を管理する」とかは、市販のソフトウェアを使った作業。いずれも、非常に高度で複雑な命令が、使用者からコンピュータに向かって発せられている。例えば、
・マウスを動かしてマウスカーソルを動かし、 ・メニューをクリックして印刷を選択して、 ・ファイルを印刷する なんていうのは、かなり複雑な「命令」の集まり。でも、多くの場合、人がコンピュータで行っている作業の多くは、「命令」を意識しなくても、「カーソルを動かす」とか「クリックする」など、利用者が理解しやすく・使いやすいように設計されている。。

 でも、本当に市販のソフトウェアを使うだけでいいのだろうか?良くないという点が、すぐに2つ思く:

1. 自分の目的にあったソフトウェアがいつも存在するというわけではない
2. ソフトが存在する場合、目的の数だけ、ソフトの使い方を覚えなければならない

特に1番目は致命的。生物学の研究で、何かの処理をしたいと考えたとき、誰かがソフトウェアを作ってくれていないと目的が達成できないということになってしまう。例えば、今日の授業で話に出てくる「遺伝的浮動」の解析ソフトなんていうのは、パソコンショップに行っても売っていない。

 そこで、この授業で次の3つを目的としてプログラミングを勉強する。

  1. 自分で作った独自の命令をコンピュータに与えて、目的を達成する
    • プログラミングを行って命令を実行させることで、初めて、コンピュータに作業をさせていることが実感できる
    • ワープロや表計算とかは、どちらかというと、道具を使って作業をさせられている感が強い
  2. プログラミングを行うことで、コンピュータができることの理解が深まる
    • あなたのコンピュータは実は、すごい性能をもっている。それを理解しておかないと使い倒せない
  3. プログラミングの過程で、コンピュータが行う処理の意味を論理立てて考えることを学べる
    • コンピュータはすごく石頭、物事を本当に論理立てて説明してやらないと、命令を聞いてくれない

 実を言うと、生物学の研究者でも、プログラミングなどを経験したことの無い人は大勢いる。今や、DNAシーケンスの決定や整列、系統樹作成にだって、専用のソフトウェアがある。。。しかし、そういうソフトウェアも、多くの場合は研究者自身が作成したもの(学生が作ったものもたくさんある)。この授業では、頭の柔らかい1年生のうちにプログラミングについての動機付けを行うことで、このクラスの中から将来は新しいソフトウェアを開発できる人が出ることも期待している。。

初めて(?)のプログラミング:"Hello World!"

「Hello World!」だなんて、なんか変なタイトル。誰が使い始めたのかは知らないが、多くのプログラミング言語の教科書で、最初に出てくるのがこのプログラム(プログラムを勉強したことのある人なら、誰でも知っている)。では、早速やってみよう。Rを立ち上げて、次のように入力。

print("Hello World!")

うまくご挨拶できただろうか?

ここでやったのは、print()という関数<注:命令とほとんど同じ意味>を使って"Hello World!"と画面に表示させただけだが、これも

画面にHello Worldと表示させる

ということを目的とした立派なプログラムだ。

「えっ?それなら、Rの最初の授業でやったオブジェクトの内容を画面に出すのもプログラミング?」と聞かれるかもしれませんが、その通り。次の囲みの中を全てコピーして、Rのコンソールにペーストしてみよう。

x=c(1,2,3,4,5,6,7,8,9,10)
sum(x)

上でやったプログラミングは、

画面に1から10までの整数の合計を表示させる

というもの。先週やったRを使った操作も、何らかの処理の結果を画面に表示させるプログラミングだったわけだ。なんとなく、プログラミングが身近になっただろうか?

複数行の命令文

上でやった2つのプログラミングは、見比べてみると違いがある。"Hello World!"の方は1行だけの命令だが、sumの方は2行になっている。プログラムは通常、いろんな処理を組み合わせて作るので、複数行になることが多い。
では3行からなるプログラムを作ってみよう。

q=c(10,15,20,25,30,35,40,45,50,55,60,65,70,80,100)
y=c(2,3,4,5,6,7,8,9,10,11,10,11,9,10,12)
plot(log10(q^2), log10(y))

このプログラムは、

2つの数値ベクトルについて計算を行って、対数グラフを描く

というものだ。使ったデータは、昨年の生物学科1年生がコドラート調査でとったデータで、面積が広くなると種数がどう増えるかを示したものだ。

Rで使う命令

 授業では一つ一つ解説するが、復習課題をやるときとか、自分で新たな解析に挑戦するときは、どういう命令があるかが書かれた説明書が必要になる。前回も紹介したが、

  • http://cse.naro.affrc.go.jp/takezawa/r-tips.pdf
    には船尾さんという方が書かれた、日本語のRの解説がある。知りたい項目はAdobe Readerの検索機能でサーチしてみよう。 また、Rを使っている最中は
    > ?plot
    > example(plot)
    という風に、?の後に関数名を打てば、説明や使用例が英語で表示される。説明文の一番最後にはExample(使用例)が載っているので、けっこう参考になる。

プログラミングの基礎: 繰り返しと代入と条件分岐 [smile]

上の例で、紹介したプログラムは、個々の命令を順番に並べて、一度にペーストしただけだった。こんなことなら、Rに命令を1行ずつ与えるのと、ぜんぜん変わらない。そこで、もっとプログラムらしい命令をRに与えてみよう。それは、繰り返し代入条件分岐というもので、プログラミングの基本中の基本。

繰り返し [smile]

人が不得意でコンピュータが得意なことの一つは、単純な繰り返し作業を際限なく(文句も言わずに)行うことだろう。つまり、プログラミングの一つの目的は、面倒な繰り返し計算をコンピュータにやらせることだと言っても言い過ぎではない。では、何回繰り返すかという命令をどうやってコンピュータに与えるかというと、 for という命令を使う。

  • 繰り返しには for() を使う
    for(i in 1:10) { print(i) }
    この命令は、
    { } で囲まれた部分の命令を10回繰り返しなさい
    というものだ。
    { } の中は何をする命令か分かるだろうか?
    
    では、上の囲みの中をコピーして、Rのコンソールにペーストしよう。
    1から10までの整数が表示された。ここでもう一度命令文をよく見てみると、3つのパートからなっている。
    for と (i in 1:10) と { print(i) } 
      for は これから繰り返し命令が始まるよということを示す
      (i in 1:10) は 繰り返しの回数が10回であることを示す
        また、iは1回の繰り返しのたびに1ずつ、10まで増加する
       もし、50回繰り返したかったら (i in 1:50) と書く
         iという文字の代わりに、jでも、kaisuでも、構わない
      { print(i) } は 繰り返しの度に{ }の中を実行せよという命令で、
        print(i)でiという変数の値を画面に表示させなさいという意味
    { }  のところは複数行に分かれていてもよく
    for(i in 1:10) {
      print(i)
    }
    と書いても結果は同じ。

なお、1:10 は

1  2  3  4  5  6  7  8  9 10

という数字の集まりを示す。次の囲みの中を1行ずつRに実行させてみよう。

1:10
x=c(1:10)
x
練習問題: 2から18までの偶数を全て表示させるプログラムをfor命令を使って作りなさい
  • プログラムのことをスクリプトとも言いう。Rのファイルメニューから「新しいスクリプト」を選ぶと、「スクリプトエディター」というエディターが開く。スクリプトエディターでスクリプトを書いてから、マウスで選択して右クリックすると、選択中のスクリプト(命令とかコードとも呼ばれる)が実行できる。
解答例:(穴埋め形式)
for(i in _:_){   # _ のところには数字が入る
  print(i*_)
}

代入 [smile]

上の for(i in 1:10) { print(i) } というプログラムでは、iの値は繰り返しの度に違う値になる。

1回目  iの値は1
2回目 iの値は2
3回目 iの値は3
....   ........
10回目 iの値は10

では、一つ前の回のiの値を使いたい場合はどうすれば良いだろうか?例えば、1から10までの合計をfor命令を使って計算することを考えると、

現在のiの値に、1つ前のiの値の合計を加えて表示させたい
1回目  iの値は1   1つ前までの合計は0  1 を表示
2回目 iの値は2   1つ前までの合計は1  3 を表示
3回目 iの値は3   1つ前までの合計は3  6 を表示
....   ........
10回目 iの値は10  1つ前までの合計は45 55 を表示

こういう場合に、代入という命令を使う。代入は、前回すでにオブジェクトへの数値やベクトルの代入で学んだように、

=

を使う。我々が通常行う計算では、'='は「3+5=8」というように、「左辺の計算結果が右辺に等しくなる」というる意味で用いられるが、プログラミングにおいては、

左辺の変数に右辺の計算結果を代入する

という意味で用いられる。上の合計の計算プログラムは次のようになる。

goukei=0           #goukeiという変数に初期値0を代入
for(i in 1:10) {   #以下を10回繰り返す
  goukei=goukei+i  #goukeiに前回までのgoukeiの値にiの値を足したもの代入
  print(goukei)    #goukeiの内容を画面に表示
} 

では、上の囲みの中をRに実行させてみよう。

上の命令の中には2箇所、代入が使われている。最初の行では、goukeiという変数に0を代入するという単純なもので、goukeiの初期値を決めている。
初期値というのも耳慣れない言葉かもしれません。プログラムに登場する変数は、最初の値が何かをはっきりコンピュータに教えてやらないと、メモリに残っている数値がそのまま使われてしまう。試しに、上のプログラムから1行目を省いたプログラムを何度か実行させてみよう。初期値が入っていないので、合計値がどんどん加算されてゆくのが分かる。

次の、goukei=goukei+iという命令文では、右辺の「goukei+i」を先に計算して左辺の「goukei」に代入している。
「右辺と左辺に同じ変数が出てくる」ところが分かりにくいかもしれないが、理解して欲しい。言葉で説明すると、

今の goukei の値に 1 を加えたものを、goukei に代入する(これまでのgoukeiは上書きされる)

という意味だ。

練習問題: 1から10までの数字を1つずつ順々にかけ合わせたた結果を全て表示させるプログラムを作りなさい
      (1x1=1, 1x2=2, 2x3=6, 6x4=24, 24x5=...... と計算してゆくということ)

以下、穴埋め形式でヒントを書いておく。_の部分(1文字とは限らない)を補ってプログラムを完成しなさい。

seki=_           #sekiという変数に初期値1を代入(かけ算だから)
for(i in 1:10) {   #以下を10回繰り返す
  _=_*_  #sekiに前回までのsekiの値にiの値を掛けたもの代入
  print(seki)    #sekiの内容を画面に表示
} 

うまくできただろうか?

縦に長くプリントされるのは格好悪いので、毎回の計算結果をオブジェクトにベクトルとして代入してから表示させてみよう

seki=1          #sekiという変数に初期値1を代入
kekka=c()         #kekkaというオブジェクトに空ベクトルを初期値として代入
for(i in 1:10) {   #以下を10回繰り返す
  seki=seki*i  #sekiに前回までのsekiの値にiの値を掛けたもの代入
  kekka=c(kekka,seki)   #kekkaというベクトルにsekiの値を要素として追加
} 
print(kekka)      #kekkaの内容を画面に表示

ここでは、計算結果を順々に保存しておく入れ物を、kekkaという名前で作成し、初期値に空ベクトル(データは無いが、ベクトル)を作っている。ベクトルの作成は、前回の授業でやったように

c()

という関数を使う。 また、ベクトルに要素を追加するにも、同じ関数 c() を使っている。 では、上の囲みの中をRに実行させてみよう。

  • 2つの代入文の比較
    上のプログラムのkekka=c(kekka,seki)と1つ前の足し算のプログラムにあったgoukei=goukei+iという2つの式はよく似た働きをしていることを理解して欲しい。
    kekka=c(kekka,seki)  kekkaにsekiを要素として追加したものをkekkaに代入
    goukei=goukei+i           goukeiにiを加えたものをgoukeiに代入
    いずれの命令でも、現在の変数の値が上書きされて変更されていることに注目。
  • せっかくRを使ってプログラミングをしているので、結果をグラフに表示させてみよう。上のprint(kekka)の部分を、plot(kekka)(あるいは、plot(log(kekka)))に変えるだけで、グラフとして出力することができる。値も表示させ対場合は、両方の命令を書いておけば良い。
    練習問題(穴埋め式):
    seki=1          #sekiという変数に初期値0を代入
    kekka=c()         #kekkaというオブジェクトに空ベクトルを初期値として代入
    for(i in 1:10) {   #以下を10回繰り返す
      seki=seki*i  #sekiに前回までのsekiの値にiの値を掛けたもの代入
      kekka=c(kekka,seki)   #kekkaというベクトルにsekiの値を要素として追加
    } 
    print(kekka)      #kekkaの内容を画面に表示
    _(log10(kekka))  #kekkaの対数をグラフにプロット
    
    ずいぶんとプログラムらしくなってきた
  • for文は2重にして使うこともできる。繰り返しのループを二重にすることで、2つの変数の総当たり計算が可能になる。
    #**次のプログラムの実行結果を予測してみよう。**
    for(i in 1:9) {   #iの値を1から9まで1ずつ変化させる
     for(j in 1:9){   #jの値を1から9まで1ずつ変化させる
        print(i*j)    #iとjを掛けたものを表示する
     }
    }

    予想できたら、実行しよう。
  • 予想通りでしたか?小学生のころ呪文のように何度も唱えものが表示されたはずだ。上のままでは縦に長く表示されて格好が悪いので、matrixという関数をつかって、ベクトルを行列に変換してで出力してみよう。

matrix()という関数はベクトルを行列に変換する働きがある。例えば、

x=c(1, 2, 3, 4, 5, 6, 7, 8, 9)

というベクトルを、3 x 3の行列に変換したいときは、

matrix(x, nrow=3, ncol=3)  #nrow= は行の数、 ncol= は列の数を指定
matrix(x, 3, 3)  #nrow=, ncol=を省略して、こういう書き方もできる

#演習:九九の表をmatrixという関数を使って表示さなさい。_を埋めなさい
result=c()                       #resultに空ベクトルを初期値として代入
for(i in 1:9) {                  #iの値を1から9まで1ずつ変化させる
 for(j in 1:9){                  #jの値を1から9まで1ずつ変化させる
    result=c(_, _*_)               #iとjを掛けたものをresultの要素として追加
 }
}
print(result)
print(matrix(result, nrow=i, ncol=j))  #iとjはそれぞれ9で終わっているので、9x9のマスになる

第10回授業の課題

  • 提出期限:6月25日水曜正午(提出期限を延ばしました)

課題1.意見調査

  1. http://bean.bio.chiba-u.jp/joho/index.php?joho20 に、「自分のID」/10 という新しいページを作成し、下の囲みの中にあるアンケートをコピー・ペーストして、「回答:」の後に答えを書き込むこと。
  • 手順
    1. 画面の上の方にある〔 新規 〕をクリック
    2. ページ名を尋ねる入力スペースが表示されるので、半角英数字で、ドット・スラッシュ・1・0を下のように入力
      ./10
    3. 下の囲みの中をコピー・ペーストし、回答や答えを書き込む
      *第10回授業・基本課題 
      **氏名:
      **課題への回答
      -今日の授業の進み方は?(はやい、丁度いい、おそい)
      --回答:
      -今日の授業の難しさはどう感じましたか(簡単 丁度いい 難しい):
      --回答:
      -難しいと答えた人は、特にどの点が難しかったですか?:
      --回答:
      -今日の授業は(分かった 半分ぐらいは分かった 分からなかった):
      --回答:
      -分からないと答えた人は、特にどの点が分からなかったですか?:
      --回答:
      -今日の講義で分からなかった用語があったら挙げてください:
      --回答:
      -授業に関する要望・質問があったらなんでもどうぞ:
      --回答:
      ***課題2.Rによるプログラミング(貼り付ける答えの行頭には半角スペースを1つ入れなさい)
      -2-1割り算の繰り返し:
       作成したプログラム:
       
       実行結果:
       
      -2-2(乱数を1つずつ20回発生させて、0.5未満のものだけ表示させるプログラム):
       作成したプログラム:
       
       実行結果:
       
      

課題2:Rによるプログラミング:繰り返しと条件分岐

次の問題文の指定にあるプログラムを作成しなさい。作成したプログラムは課題提出ページに貼り付けなさい。 行頭には必ず半角の空白を入れること(K2Editorで正規表現検索・置換を行えば可能です)。
なお、2, 3番の課題の乱数発生には、

runif(1)

を使いなさい。

  1.  50を5で割り得られた結果を表示し、その数字をまた5で割るという操作を10回繰り返すプログラムを、繰り返し文( for(i in 1:10))を使って作成しなさい。
  2.  乱数を1つずつ20回発生させて、0.5未満のものだけを画面に表示させるプログラムを、繰り返し文(for)と条件分岐(if)を使って作成しなさい。

Last-modified: 2015-05-13 (水) 16:42:04 (3268d)