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

## はじめに
この記事では，モンティ・ホール問題をシミュレーションし，解析解が正しいのか確認する．この問題の解は直感と合わないため，理解することが難しかった．「それなら実際にやってみよう！」ということである．

##モンティ・ホール問題とは？ -アメリカのテレビ番組の企画-
３つの扉がある．その中のうち，１つは当たりが入っている．挑戦者は１つの扉を選ぶ．もちろん挑戦者はどこに当たりがあるか知らない．そのあと番組側は，挑戦者が選んでない扉かつ当たりが入っていない扉を開ける．
ここで挑戦者はもう一度，扉を選択することができる．今まで選んだ扉を選び続けるか（スティック），それとも選ぶ扉を変えるか（スイッチ）．
ここでスティックした時とスイッチした時どちらの方が当たりの扉を選ぶ確率は上がるだろうか？


例）
挑戦者は最初に1の扉を選ぶ．正解は2の扉である．番組側は3の扉を開く．
挑戦者は選択する扉を1or2から選ぶ．ここでスティックするかスイッチするか．

あなたが挑戦者ならどうするだろうか？

## 解析的に解く
ベイズの定理を用いて解く
簡単にいうと，事前確率から事後確率を推測する定理である．
P(B|A)...Aが起こったという条件下でBが起きる確率
P(A|B)...Bが起こったという条件下でAが起きる確率
P(A)...Aの起こる確率
P(B)...Bの起こる確率
とすると

```math
P(B|A) = \frac{P(A|B)P(B)}{P(A)}
```
ベイズの定理を用いて解析的に解いていく．
例の場合を考える．

```math
A:番組側が扉を開ける確率 \\
B_1:1の扉に当たりがある確率 \\
B_2:2の扉に当たりがある確率 \\
B_3:3の扉に当たりがある確率 \\
```

とする．
それぞれの確率を求めていく．まずは$B_1$ ,$B_2$ ,$B_3$の確率はそれぞれ$\frac{1}{3}$(３つの扉のうち１つに当たりがある）．次に$P(A|B_1)$($B_1$に当たりがある時に3の扉を開ける確率）は挑戦者が１の扉を選んでいるので番組側は2or3の扉を開く．なので$P(A|B_1)$は$\frac{1}{2}$（2or3のどちらかの扉を開く）となる.また$P(A|B_2)$(は2の扉に当たりがあるので3が開けられる確率は1(1の扉は挑戦者が選んでいるので開けない，2の扉には正解があるので開けない）である．最後に$P(A|B_3)$は３の扉に正解があるので３の扉が開かれることはない．なので$P(A|B_3)$は0である．
以上のことより，3の扉が開く全ての確率を足すと

```math
P(A)=P(A|B_1)P(B_1)+P(A|B_2)P(B_2)+P(A|B_3)P(B_3) \\
=\frac{1}{2}\times\frac{1}{3}+1\times\frac{1}{3}+0\times\frac{1}{3} \\
P(A)=\frac{3}{6}
```

ベイズの定理より，3の扉が開いた時$B_1$に当たりがある確率は

```math
P(B_1|A)=\frac{P(A|B_1)\times P(B_1)}{P(A)} \\
=\frac{\frac{1}{2}\times\frac{1}{3}}{\frac{3}{6}} \\
= \frac{1}{3}
```

ベイズの定理より，3の扉が開いた時$B_2$に当たりがある確率は

```math
P(B_2|A)=\frac{P(A|B_2)\times P(B_2)}{P(A)} \\
=\frac{1\times\frac{1}{3}}{\frac{3}{6}} \\
= \frac{2}{3}
```
以上の結果より３の扉が開かれたという情報を知った場合，スイッチした方がスティックした方が2倍当たる確率が高いということが示された．

### 直感と反する？？？
３つの扉から1つを選ぶ．１つの扉が開かれる．残った2つの扉から選び直す．　=> 　2つの扉から1つを選ぶので確率は$　\frac{1}{2}$なのではないか？？

## シミュレーション
直感と反するなら実際にその状況を作って繰り返してみよう！ とりあえず10万回試行してみた．ファイルを分けるのが面倒だったため，
選択肢を変える場合を観測する　→　rechoice = leave(challengerChoice)　，print("選択肢を変えない場合",p)　の行をコメントアウトする
選択肢を変えないを観測する　→　rechoice = reChoice(challengerChoice,door)　，print("選択肢を変えた場合",p)　の行をコメントアウトする

```python
import random

#開く扉を決める
def decisionOpenDoor(challengerChoice,door):
    judge = False

    while judge == False:
        openDoor = random.randint(0,len(door) - 1)
        if openDoor == challengerChoice:  #挑戦者が選んだdoorは開けない
            pass
        elif door[openDoor] == 1: #正解のあるdoorは開けない
            pass
        else:
            door[openDoor] = 'x'
            judge = True

    return door

#選択肢を変えた場合
def reChoice(challengerChoice, door):
    for i in range(len(door)):
        if door[i] == 1:
            option_1 = i
        elif door[i] == 0:
            option_2 = i
        else:
            pass

    if challengerChoice == option_1:
        rechoice = option_2
    elif challengerChoice == option_2:
        rechoice = option_1

    return rechoice

#選択肢を変えない場合
def leave(challengerChoice):

    rechoice = challengerChoice

    return rechoice

#正解をカウント
def checkAnswer(rechoice,door,count):

    if door[rechoice] == 1:
        count += 1
    else:
        pass
    return count

def main(loop):
    count = 0

    for i in range(loop):
        door = [ 0, 0, 1]

        random.shuffle(door)

        challengerChoice = random.randint(0,len(door) - 1)

        door = decisionOpenDoor(challengerChoice, door)

        rechoice = reChoice(challengerChoice,door) #選択を変える場合
        rechoice = leave(challengerChoice) #選択を変えない場合

        count = checkAnswer(rechoice, door,count)

    p = count/loop
    print("選択肢を変えた場合",p)
    print("選択肢を変えない場合",p)


if __name__ == "__main__":
    main(100000)
```

###　結果
```
選択肢を変えた場合 0.66658 
選択肢を変えない場合 0.33245 
```

## まとめ
解析的に求めた解とシミュレーションで求めた解が一致することが確かめられた．直感では完全に$\frac{1}{2}$だと思っていた．「扉が開いた」という情報を知ることで得られる恩恵は選択肢が削れるという直接の結果だけではないということが示された．情報の重要性を感じることができた．
選択肢を変えた場合のロジックがいい案が思いつかず，冗長なコードになってしまった．今回学んだことは`random．shuffle(door)`で`door`に代入するとNoneが返ってくることである．

誤字・脱字があればご報告いただけると幸いです🙇‍♂️また分からない，理解しづらい文があればコメントください🙇‍♂️