【モンティーホール問題】初心者が数学の問題をPythonで解く

# 概要

数学の問題に「モンティーホール問題」というのがあります
これをPythonで統計を取って解いてみるということをします

注意）結構アバウトに検証します。

# モンティーホール問題とは

Wikipediaからの引用です

>モンティ・ホール問題（モンティ・ホールもんだい、英: Monty Hall problem）とは、確率論の問題で、ベイズの定理における事後確率、あるいは主観確率の例題の一つとなっている。モンティ・ホール（英語版）（Monty Hall, 本名：Monte Halperin）が司会者を務めるアメリカのゲームショー番組、「Let's make a deal（英語版）[注釈 1]」の中で行われたゲームに関する論争に由来する。一種の心理トリックになっており、確率論から導かれる結果を説明されても、なお納得しない者が少なくないことから、本項～プロブレムの他、～ジレンマあるいは～パラドックスとも称される。「直感で正しいと思える解答と、論理的に正しい解答が異なる問題」の適例とされる。

<a src="https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%83%86%E3%82%A3%E3%83%BB%E3%83%9B%E3%83%BC%E3%83%AB%E5%95%8F%E9%A1%8C">【Wikipedia】モンティーホール問題</a>

ここで要点をまとめる。モンティーホール問題とは、

```
- 数学、確率論の問題
- アメリカのゲームショー番組中に行われたゲームの一つ
- 名前は司会者の名前に由来する
- 多くの考えから導かれる「良いとされる選択」と確率論から導かれる「良いとされる選択」に乖離がある
```

具体的な問題は以下となる
Wikipediaから引用

>プレーヤーの前に閉じた3つのドアがあって、1つのドアの後ろには景品の新車が、2つのドアの後ろには、はずれを意味するヤギがいる。プレーヤーは新車のドアを当てると新車がもらえる。プレーヤーが1つのドアを選択した後、司会のモンティが残りのドアのうちヤギがいるドアを開けてヤギを見せる。
ここでプレーヤーは、最初に選んだドアを、残っている開けられていないドアに変更してもよいと言われる。
ここでプレーヤーはドアを変更すべきだろうか？

<a src="https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%83%86%E3%82%A3%E3%83%BB%E3%83%9B%E3%83%BC%E3%83%AB%E5%95%8F%E9%A1%8C">【Wikipedia】モンティーホール問題</a>

# 計算

さて一度、予想を立てずに計算してみる
以下のような流れにした

```python
import random

def check():
    door_list = [0, 0, 0] #ドアを作る
    car = random.randint(0,2) #正解の場所を決定（０～２番目の扉のどれか）
    door_list[car] = 1 #正解の要素を1にする

    pick = random.randint(0, 2) #選ぶ場所を決定
    hint = random.randint(0,2) #ヒントとして与えられる場所を決定
    while( (hint == pick) or (hint == car) ): #ヒントが選んだ場所か当たりの場合、
        hint = random.randint(0,2) #もう一回ヒントを決定する

    change = random.randint(0,2) #変更する際の場所を決定
    while( (change == hint) or (change == pick) ): #変更する際の場所が選んだ場所かヒントの場所の場合、
        change = random.randint(0,2) #もう一回変更する際の場所を選ぶ

    if(car == change): #もし、当たりと変更した際の場所が同じだったら、
        return("yes") #yesを返す
    else: #もし、違ったら、
        return("no") #noを返す

def run(run_time):
    n_yes = 0 #Yesが出た際のカウントを初期化
    n_no = 0 #Noが出た際のカウントを初期化
    error = 0 #エラーが出た際のカウントを初期化

    for i in range(run_time): #施行する回数の分だけ、
        rtn = check() #check()関数を行い、戻り値をrtnに代入
        if (rtn == "yes"): #もし、rtnがyesだったら、
            n_yes = n_yes + 1 #yesが出た際のカウントに１を足す
        elif (rtn == "no"): #もし、rtnがnoだったら、
            n_no = n_no + 1 #noが出た際のカウントに１を足す
        else: #それ以外であれば、
            error = error + 1 #errorに1を足す

    print("changed and :) > " + str(n_yes)) #変更してあってた事象数の出力
    print("changed but :( > " + str(n_no)) #変更して間違ってた事象数の出力
    if (error != 0): #もし、エラーの回数が０で無かったら
        print("error > " + str(error)) #エラーの回数を出力
        
run(300000) #300000回試行する
```

やってみた結果

1回目

```
=============== RESTART: C:/Users/###/Desktop/problem.py ==============
changed and :) > 200116
changed but :( > 99884
>>>
```

2回目

``` 
=============== RESTART: C:/Users/###/Desktop/problem.py ==============
changed and :) > 199682
changed but :( > 100318
>>> 
```

3回目

```
=============== RESTART: C:/Users/###/Desktop/problem.py ==============
changed and :) > 200107
changed but :( > 99893
>>> 
```

明らかに変更した方がよいことが分かった！
大体、2倍も違うのか....

# なぜ変更すべきか

必ず選択を変えた際に起こる事象

```
１）最初に当たりを選ぶ→はずれが教えられる→選択を変える→外れる
２）最初にはずれを選ぶ→はずれが教えられる→選択を変える→当たる
３）最初にはずれを選ぶ→はずれが教えられる→選択を変える→当たる
```

必ず選択を変えない際に起こる事象

```
１）最初に当たりを選ぶ→はずれが教えられる→選択を変えない→当たる
２）最初にはずれを選ぶ→はずれが教えられる→選択を変えない→外れる
３）最初にはずれを選ぶ→はずれが教えられる→選択を変えない→外れる
```

つまり、選択を変えた際には2/3の確率で当たり、変えなかった際には1/3の確率で当たるということ！
ここからプログラムで求めた「2倍も違う」が裏付けられます

# まとめ

数学の問題をプログラムで解くと面白いです
いつかどこかで役立ててください
おしまい