確率と統計​/コードで数え上げる

Unity学習帳2冊目確率と統計 / コードで数え上げる

コードで数え上げる anchor.png

確率の問題を考える

コインを50回投げて表が連続8回、裏が連続8回と続けて出る確率は幾らか?

まず、問題の規模を小さくして考え易くする
コインを6回投げて表表裏裏と続けて出る確率は幾らか?
と言った風に考える

PCとプログラムコードを利用して問題解決を試みる
まず実際にその事象の数を「数え上げて」みる

表をHead、'H'、裏をTail、'T'の一文字に抽象化して、その順列をコードで出力する
この出力に対して希望する条件に見合った事象を検索に掛け、その数を数え上げる

連続で変化する試行回数に沿って、その数の変化を観察し、その性質を見抜く
その上で、見抜いた性質に対し未来予測を試みて、実際にプログラムコードでシミュレーションし
その考えが正しいか否かを確認する。この一連の工程を通して計算した確率が「確からしい」事を確認する
(アプローチとしては理科の実験のように実際に体験していく形になっている)

Page Top

問題を小さくして考える anchor.png

まず、コインを4回投げた状態の順列を出力する。この場合、表表裏裏と言う事象は"HHTT"で表され、その順列は16事象中1事象となる筈だ。それを確認してみる。全体の順列を出力するプログラムコードは以下となる。このコードは帰納の考えを利用している。つまり数学的帰納による証明が行い易く、微積分に考えを転用しやすい。そのために帰納で作ったとも言えるし、運用性の点から帰納で作ったとも言える

Page Top

Perm.cs anchor.png

Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 
 
 
 
 
 
 
-
|
-
|
|
|
|
|
-
!
|
|
!
|
-
!
-
|
|
|
|
-
|
|
|
!
|
|
!
|
-
!
-
|
|
-
|
-
|
|
|
!
!
-
|
!
!
|
-
|
!
-
!
-
|
-
|
-
|
!
!
!
!
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
 
public class Perm : MonoBehaviour
{
    void Start()
    {
        int length = 4;
        char[] set = { 'H', 'T' };
 
        List<string> strList = Root(set, length);
 
        //全順列を網羅してファイル出力
        string folder = Application.dataPath;                   //これだけでunityの実行ファイルがあるフォルダがわかる
        SaveText(folder, @"\順列.txt", strList.ToArray());
 
    }
 
    //基底部
    List<string> Root(char[] set, int length)
    {
        List<string> strList = new List<string>();
        int level = 0;
 
        for (int i = 0; i < set.Length; i++)
        {
            char[] dat = new char[length];
            dat[0] = set[i];
            Loop(dat, level, set, strList);
        }
 
        return strList;
    }
 
    //帰納部
    void Loop(char[] dat, int level, char[] set, List<string> strList)
    {
        level++;
        if (level < dat.Length)     //帰納関数の終了条件
        {
            for (int i = 0; i < set.Length; i++)
            {
                char[] cloneDat = (char[])dat.Clone();  //オブジェクトを複製する
                cloneDat[level] = set[i];
                Loop(cloneDat, level, set, strList);    //帰納関数には複製された参照値が渡される為、呼び出し元側の値が書き換えられることは無い
            }
        }
        else {
            strList.Add(new string(dat));
        }
    }
 
    //資料:StreamWriter クラス (System.IO)
    //http://msdn.microsoft.com/ja-jp/library/system.io.streamwriter(v=vs.110).aspx
 
    //テキストファイルとしてセーブ
    public void SaveText(string fileFolder, string filename, string[] dataStr)
    {
        using (StreamWriter w = new StreamWriter(fileFolder + filename, false, System.Text.Encoding.GetEncoding("shift_jis")))
        {
            foreach (var item in dataStr)
            {
                w.WriteLine(item);
            }
        }
    }
}

これに対する出力ファイルの内容は以下となっている。VisualStudioでこのテキストファイルを開く。Ctrl+fで検索ウインドウを開き正規表現を使用するモードにして「HHTT」を検索すると、一つ見つける事が確認できる(正規表現(regex)モードにすると複数のラインが条件を満たした場合、複数のラインをマークする)

HHHH
HHHT
HHTH
HHTT
HTHH
HTHT
HTTH
HTTT
THHH
THHT
THTH
THTT
TTHH
TTHT
TTTH
TTTT

ここでコインを4回連続で投げた場合、全体16、表表裏裏(HHTT)が出る事象は1という事で確率が1/16である事が分かる。続けてコインを投げる回数を増やして、それぞれの回数でHHTTが出てくる回数を記録していく。投げる回数はコード内11行目、Start関数内のlengthの値を変更することで出来る

       int length = 5;

この4のところを5,6,7,...と変更して検索を掛け回数を記録する。5を指定すると以下になる

samp1.png

ある程度の回数まで進むと手動で検索するのが面倒になってくる
そこでコードを書いてプログラムに検索させる

Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
 
-
|
|
|
|
|
-
!
|
|
-
!
|
|
|
|
!
    void Start()
    {
        int length = 7;
        char[] set = { 'H', 'T' };
 
        List<string> strList = Root(set, length);
 
        //全順列を網羅してファイル出力
        string folder = Application.dataPath;                   //これだけでunityの実行ファイルがあるフォルダがわかる
        SaveText(folder, @"\順列.txt", strList.ToArray());
 
        //文字列の中に"HHTT"がある行を抜き出す
        var queary = strList.AsQueryable().Where(item => item.Contains("HHTT"));
        var queList = queary.ToList();
        queList.Add("検索前総数" + strList.Count().ToString());
        queList.Add("カウント数" + (queList.Count-1).ToString());
        SaveText(folder, @"\HHTT抜き出し.txt", queList.ToArray());
    }

これを16回ぐらいまで記録して以下のような表を作った

4回5回6回7回8回9回10回11回12回13回14回15回16回
1/164/3212/6432/12879/256186/512424/1024944/20482065/40964456/81929512/1638420128/3276842287/65536

これを分母を揃えて数列にすると

\(\frac { 4096 }{ 65536 } ,\frac { 8192 }{ 65536 } ,\frac { 12288 }{ 65536 } ,\frac { 16384 }{ 65536 } ,\frac { 20224 }{ 65536 } ,\frac { 23808 }{ 65536 } ,\frac { 27136 }{ 65536 } ,\frac { 30208 }{ 65536 } ,\frac { 33040 }{ 65536 } ,\frac { 35648 }{ 65536 } ,\frac { 38048 }{ 65536 } ,\frac { 40256 }{ 65536 } ,\frac { 42287 }{ 65536 } \)

となる。この分子の変化の様子を観察すると4~7回目まで4096の等差数列だが、8回目から妙なズレが生じ始める。この性質を見抜きたいが、その前にこの値が正しい確率を導くものなのか、その根拠を確かめておく
実際にコンピューター内で50%ずつ表裏がランダムに出るコインを指定回数投げてHHTTが出た回数を数える。このコードは以下になる

Page Top

niji_prob.cs anchor.png

Everything is expanded.Everything is shortened.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 
 
 
 
 
 
-
|
|
-
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
!
|
!
!
|
-
!
-
|
|
|
!
|
-
!
-
|
-
|
!
|
!
|
-
!
-
|
|
!
|
!
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
 
public class niji_prob : MonoBehaviour
{
 
    void Start()
    {
        int sampling = 10000;
        int tossCount = 4;
        float headPercentage = 0.5f;
        string hitString = "HHTT";
 
        char[] coinList = new char[tossCount];
 
        for (int j = 0; j < 5; j++)
        {
            int successCount = 0;
 
            for (int i = 0; i < sampling; i++)
            {
                coinList = GetCoinTossTest(coinList, headPercentage);
                if (new string(coinList).Contains(hitString)) successCount++;      //文字列検索してマッチすればtrueを返しカウントアップ
            }
            print((double)successCount / (double)sampling);
        }
    }
 
    //動作確認用メソッド
    private void SimpleMethod(float headPercentage, string hitString, char[] coinList)
    {
        coinList = GetCoinTossTest(coinList, headPercentage);
        print(new string(coinList));
        print(new string(coinList).Contains(hitString));
    }
 
    //コイントス試行
    public char[] GetCoinTossTest(char[] coinList, float headPercentage)
    {
        for (int i = 0; i < coinList.Length; i++)
        {
            coinList[i] = TossCoin(headPercentage);
        }
        return coinList;
    }
 
    //指定した表の確率でコイントスして表が出たら'H'(表:Head)、裏で'T'(裏:tail)を返す
    public char TossCoin(float headPercent)
    {
        if (Random.value < headPercent) return 'H';
        return 'T';
    }
 
}

計算通りであるならばコインを4回投げた場合、1/16=0.065となる筈。おおよそその辺り周辺の値をフラフラしていれば、ほぼ正しいと考えられるだろう。出力結果は以下となった
ほぼ予想通り

0.0642
0.0652
0.06
0.0619
0.0606

続けて12行目の

       int tossCount = 5;

を「5」に変更してコインを投げる回数を変えて、確率があっているかを確認する。同様に回数を例えば32や72などユニークな値にして値が合うかどうかを確認する
問題ない様だ

Page Top

性質 anchor.png

数列を観察し以下の性質を推理した

\(\begin{matrix} 4回目 & \frac { 1 }{ 16 } \\ 5回目 & \frac { 2 }{ 16 } \\ 6回目 & \frac { 3 }{ 16 } \\ 7回目 & \frac { 4 }{ 16 } \\ 8回目 & \frac { 5 }{ 16 } -\frac { 1 }{ 256 } \\ 9回目 & \frac { 6 }{ 16 } -\frac { 3 }{ 256 } \\ 10回目 & \frac { 7 }{ 16 } -\frac { 6 }{ 256 } \\ 11回目 & \frac { 8 }{ 16 } -\frac { 10 }{ 256 } \\ 12回目 & \frac { 9 }{ 16 } -\frac { 15 }{ 256 } +\frac { 1 }{ 4096 } \\ 13回目 & \frac { 10 }{ 16 } -\frac { 21 }{ 256 } +\frac { 4 }{ 4096 } \\ 14回目 & \frac { 11 }{ 16 } -\frac { 28 }{ 256 } +\frac { 10 }{ 4096 } \\ 15回目 & \frac { 12 }{ 16 } -\frac { 36 }{ 256 } +\frac { 20 }{ 4096 } \\ 16回目 & \frac { 13 }{ 16 } -\frac { 45 }{ 256 } +\frac { 35 }{ 4096 } -\frac { 1 }{ 65536 } \\ \vdots & \vdots \end{matrix}\)

性質を見出すいくつかの方法

  • グラフを視覚的に確認して、その描く線の軌跡が「なんの関数グラフに似ているか」で推測を立てる
  • 階差数列を計算して、その値の変異を観察し推測する

ここでgoogleスプレッドシートを利用して4重に階差数列を導き出し、その値の変化を観察して、その性質を見出した
以下のリンクを参照してほしい
sc1.png
googleスプレッドシートを利用して作った階差数列の表

左隣のひとつ前のセルと次のセルを関数で引算して差を計算して等差数列を導き出している。それを4層に渡り繰り返している
このようにマイクロソフトのエクセルやグーグルのスプレッドシートの機能を利用することで比較的短時間に数列の性質を見抜くことができる
ここから数式に直したり、その仕組みを調べて考える行動に移すことができる

では、これを数式に直し「この考えが正しいかどうか」を検証する


添付ファイル:
filesc1.png 20件 [詳細] filesamp1.png 21件 [詳細]

トップ   差分 バックアップ 複製 名前変更 リロード   ページ新規作成 全ページ一覧 単語検索 最新ページの一覧   ヘルプ   最新ページのRSS 1.0 最新ページのRSS 2.0 最新ページのRSS Atom
Last-modified: 2016-06-28 (火) 02:37:37 (JST) (2865d) by osinko