2020年4月26日

Rで大数の法則を感じる(cumsum, sample)

今回は、コインを繰り返し投げて表が出る確率を検証します。わずか10行のコードですので、はじめての人も簡単にできます。

目次
  1. コイン投げの確率
  2. sample
  3. コイン投げの検証

*  *  *

1 コイン投げの確率

コインを投げると表か裏がでます。コインに歪みがなければ、表と裏が出る確率はそれぞれ50%のはずです。

では、歪みがないコインを10回投げたら5回だけ表が出るでしょうか。100回投げたら50回だけ表が出るでしょうか。200回、300回、400回投げつづけたら何回表が出るでしょうか。

本当に投げた回数の50%だけ表が出るの?

今回のコードは、この疑問を検証します。

*  *  *

2 sample

私たちは、おなじことを何度も繰り返すと飽きておざなりになってしまいますが、コンピューターは繰り返し作業がとても得意です。100回、1000回繰り返しても正確無比なままです。私たちが苦手でコンピューターが得意なことは、コンピューターにやってもらいましょう。

Rでは、sample という関数で繰り返し作業を命じます。たとえば、コイン投げを100回繰り返す命令文は次のとおりです。

sample(x=c(0,1), size=100, replace=TRUE)

x=c(0,1) はコイン投げで裏が出ることを数字の0、表が出ることを数字の1と定義しています。0と1が出る確率はそれぞれ50%です。size=100 はコインを100回投げる指定、replace=TRUE は毎回コインを投げ直す指定です。「コインを投げ直す」ことについては、この記事の一番下の補論で説明します。興味のある人はみてください。そこまで興味がない人は、迷わずこのように書きましょう。

*  *  *

3 コイン投げの検証

コイン投げのコードは次のとおりです。コードを入力して実行してみてください。













うまくいけば、右下の領域に次のようなグラフがあらわれます。グラフの形はコイン投げの結果次第ですので実行のたびに変わりますが、似たグラフが出てくるはずです。


横軸はコイン投げの回数です。100は100回投げたことを、700は700回投げたことを表します。私たちがコインを700回投げるのはとても大変ですが、Rなら1秒で終わります。

縦軸は表が出る確率(相対頻度)です。100回くらい投げたとき、表が出たのは50回くらいでした。その後、300回くらいまでのあいだ、表が出る確率は少し低くなりました。300回を超えると、表が出る確率は50%前後で安定しているようにみえます。

300回投げれば150回くらい、400回投げれば200回くらい、…、700回投げれば350回くらい表が出ています。「まったく同じ条件で、まったく同じ実験を、とてもたくさん繰り返す」と、その平均は真の値に近づいてゆきます。これを大数の法則といいます。大数の法則は難しい統計の概念ですが、Rでグラフを書けば、点線にだんだん近づくことだとイメージできます。

*  *  *

以下、準備、処理、出力の順でコードを説明します。まず準備からです。2行目の rm(list=ls()) と3行目の ls() はいつものおまじないです(はじめての人は右のラベルから rm(list=ls()) をクリックしてみてください)。4行目の n=700 はコインを投げる回数です。





*  *  *

つづいて処理です。たった2行です。6行目はコイン投げの結果を記録する命令文です。裏が出たら0、表が出たら1を記録します。コインを700回投げますので、toss には0または1が合わせて700個記録されます。7行目は、6行目の toss に記録されたコイン投げの結果を足し上げる命令文です。たとえば、1回目に裏、2回目に表、3回目に表、4回目に裏が出たとしましょう。これは6行目の toss に次のように記録されます。

toss={0, 1, 1, 0, ...}

これを7行目で足し上げると

toss=cumsum(toss)={0, 1, 2, 2, ...}

となります。このように toss を定義し直します。たった2行ですが、多くの作業が含まれています。






*  *  *

さいごに出力です。これもたった2行です。9行目は折れ線グラフを書く命令文です。(1:n) は 1から n まで整数をならべる命令文です。7行目で定義した toss と (1:n) を示すと

toss={0, 1, 2, 2, ...}
(1:n)={1, 2, 3, 4, ...}

toss/(1:n) は上段の数を下段の数でそれぞれ割る命令文ですので

toss/(1:n)={0, 1/2, 2/3, 2/4, ...}

となります。2つめと4つめの値は理論上の確率50%と等しいです。9行目だけで、コインを投げる回数それぞれで表が出る確率を計算して、結果をグラフにすることができます。

10行目は理論上の確率50%(0.5)を描き加える命令文です。lty=3 は、グラフを点線で描く指定です。




*  *  *



補論 replace=TRUE について

6行目の命令文にある replace=TRUE は毎回コインを投げ直す指定です。高校の確率の授業で学んだ「袋から白玉、赤玉を取り出す」試行では、TRUE は袋から取り出した玉を袋に戻すことにあたります。このとき、白玉を取り出す確率は毎回変わりません。

これを replace=False とすると、取り出した玉を袋に戻さないことになります。取り出すたびに袋に残る玉は減りますので、白玉を取り出す確率は変わります。コイン投げであれば、表が出たら、残りは裏しか出ようがありませんので、裏が出る確率は100%になってしまいます(同様に、裏が出た後表が出る確率も100%になります)。そして、表と裏(あるいは裏と表)が出たら、ほかに出るものがないのでプログラムは止まってしまいます。私たちはコイン投げを何度も繰り返したいので、replace=TRUE と指定します。