2016年4月23日土曜日

モンティホール問題をシミュレーションしてみる

最近、統計学にハマってるので、有名なモンティホール問題をベイズの定理で解いてみる
また、プログラムも組んで理論解と数値解の比較もしてみる
モンティ・ホール問題
3つの箱があり、その内1つにアタリがある
最初に自分は箱を1つ選ぶ
その後、司会者は「自分が選んだ箱」以外からハズレの箱を1つ公開する
自分は箱を選び直す権利があるが、選び直すべきか?

直感的には選び直しても確率は変わらないように思えるが、選び直すのが正解
いつ見ても不思議な問題w

 理論解(ベイズの定理)
箱をそれぞれ、箱1、箱2、箱3とする
自分は箱1を選択し、司会者が箱2をハズレ宣言したとき、それぞれの箱のアタリの確率を求める
事象$A$:箱1にアタリが入っている
事象$B$:司会者が箱2をハズレだと宣言する
とすると、それぞれの箱のアタリが入っている確率は、
    ・箱1
    $P(A|B)$
    ・箱2
    $0$
      (∵司会者は箱2がハズレと宣言してる)
    ・箱3
    $1-P(A|B)$
      (∵上記の余事象)
となり、箱1にある確率は「再選択しない時のアタリ率」、箱3にある確率は「再選択時のアタリ率」となる


箱1のアタリ確率はベイズの定理より \[ P(A|B)=\frac{P(B|A) P(A)}{P(B)} \]
$P(A)$は「箱1にアタリが入っている」確率なので \[ P(A)=\frac{1}{3} \]
$P(B|A)$は「箱1がアタリのとき、司会者が箱2を選ぶ」確率
箱1がアタリで、かつ自分は箱1を選んでいるため、司会者の選択肢は箱2、箱3の2択になる。よって \[ P(B|A)=\frac{1}{2} \] $P(B)$は「司会者が箱2をハズレだと宣言する」確率
箱1を自分が選んでいるため、司会者の行動は下記の4通りになる
    ・箱1がアタリの場合は2通り(箱2or箱3)
    ・箱2がアタリの場合は1通り(箱3のみ)
    ・箱3がアタリの場合1通り(箱2のみ)
このとき、箱2が選択できるのは2通り
よって \[ P(B)=\frac{2}{4}=\frac{1}{2} \] 以上より、
箱1にアタリがある(再選択せずにアタリを引く)確率は
\[ P(A|B)=\frac{P(B|A) P(A)}{P(B)}=\frac{\frac{1}{2}\frac{1}{3}}{\frac{1}{2}}=\frac{1}{3} \] 箱3にアタリがある(選び直してアタリを引く)確率は \[ 1-P(A|B)=1-\frac{1}{3}=\frac{2}{3} \]
よって、
選び直した方がアタリの確率が高い

 数値解(モンテカルロ法)
C++で組むとこんな感じ。一応、箱の数が3つ以上の場合にも対応した作り
再選択をしないパターンだと、結果がわかりにくいので、「再選択したときのアタリ確率」を求める
/**
 MontyHall.cpp
 Monty Hall問題で、再選択時のアタリ確率
*/
#include<iostream>
#include<cstdlib>

#define N   50000000 // 試行回数
#define NUM 3        // 箱の数

int main() {
    // 正解数をカウント
    long count = 0;

    // 試行回数分ループ
    for(long i = 0; i < N; i++) {

        // 箱の作成
        bool box[NUM];
        for(int n = 0; n < NUM; n++) box[n] = false;
        box[rand()%NUM] = true;

        // 自分の選択
        int my_select = rand() % NUM;

        // 司会者の選択
        int order_select;
        do {
            order_select = rand() % NUM;
        } while(order_select == my_select || box[order_select]);

        // 解の変更
        int change_select;
        do {
            change_select = rand() % NUM;
        } while(my_select == change_select || order_select == change_select);

        // 結果
        if(box[change_select]) count++;
    }
    std::cout<< "結果:"<< (double)count / N << std::endl;
    return 0;
}
結果は
$ g++ MontyHall.cpp
$ ./a.out
結果:0.666652
分数にすると「2/3」になる
やはり、理論解と一致した

 結論
モンテホール問題は選び直した方が確率が高くなる
しかし、
いろんな確率の本を読んでいると、主観依存だから(ryとか、モデルの設定で変わるから(ryとか
もはや哲学の域で「確率とは何なのか」って感じで発狂したくなる
いろいろな解釈があるけど、数値解でも同様の結果になることから、僕は「確率は上がる」と主張したい

0 件のコメント:

コメントを投稿