モンティ・ホール問題を今さらPythonで検証してみる

# Ⅰ. モンティ・ホール問題　　
　モンティ・ホール問題をここで解説するのは蛇足かと思いますが、「なんじゃそれ？」という方に簡単にご紹介を。モンティ・ホール問題とは、アメリカで放送されたゲーム番組で行われたゲームに由来する、アメリカで大議論を呼んだ問題だそうです。ちなみに、その番組の司会を務めた方がモンティ・ホールさんという肩とのこと。  
　問題のゲームですが、3つのドアが提示されその中の一つが当たり。プレーヤーはその中から一つのドアを選択するのですが、その後司会のモンティ・ホールさんが、残った２つのドアのうちハズレのドアを１つ解放して見せます。それを見た後で、プレーヤーは一度だけドアを選択し直すことができるというもの。  
　ここで、選択したドアを変えるのと変えないのとで、どちらの方が当たりを引く確率が高くなるのかという点について、大きな議論を巻き起こしたものがモンティ・ホール問題と呼ばれているものです。  
  
# Ⅱ. ネタバレと疑問  
　結論としては、このゲームにおいては選択したドアを変える方が約２倍当たりになる確率が高くなるというところで、決着がついています。自分としては、ドアを変えて当たりになる確率vsドアを変えずに当たりになる確率という構図で考えると、ドアを変えて当たりになるには最初にハズレのドアを選択している必要があり、逆にドアを変えずに当たりになるには最初から当たりを選択していなくてはならないため、この結論には納得がいくものでした。  
　この問題を説明しているサイトなどあれこれ見ていると、この最初のドアを１００個で考えればわかりやすいという解説をよく目にします。しかし、自分の理解ではドアが3つの方が理解がしやすく、ドアを１００個にするとメリットがわかりにくくなるように感じていました。  
　というわけで、このモンティ・ホール問題を今さらながら検証してみようと思った次第です。  
  
# Ⅲ. ゲームを再現する  
```Python
# 一連の流れを関数化する。今回は３択で検証する
def montyhall(change=True):
    target_list = list(range(1, 4))
    target = random.choice(target_list)
    select_number = random.choice(target_list)
    open_box_list =  list(filter(lambda x:(x != target) & (x !=select_number), target_list))
    open_box = random.choice(open_box_list)
    if change == True:
        select_number = random.choice([s for s in target_list if (s != select_number) & (s != open_box)])
    if select_number == target:
        return 1
    else:
        return 0

# 関数を使用して１０００回試行し、当たりの確率を比較する
change_result = []
no_change_result = []
for _ in range(1000):
    change_result.append(montyhall(True))
for _ in range(1000):
    no_change_result.append(montyhall(False))

change_hit = len(list(filter(lambda x:x == 1, change_result)))
no_change_hit = len(list(filter(lambda x:x == 1, no_change_result)))

print(f'途中で選択を変えた場合の正解率は{(change_hit/len(change_result))*100}%です')
print(f'途中で選択を変えなかった場合の正解率は{(no_change_hit/len(no_change_result))*100}%です')
```  
この実行結果は...  
**途中で選択を変えた場合の正解率は66.4%です**
**途中で選択を変えなかった場合の正解率は33.300000000000004%です**
となり、やはり途中でドアを変えた方が当たりを引く確率は約２倍となることがわかります。  

# Ⅳ. ドアの数を増やしていって、当たりになる確率を比較する  
```Python
# 同じことを選択肢の数を増やして検討してみる
def mmontyhall_n(n, change=True):
    target_list = list(range(1, n+1))
    target = random.choice(target_list)
    select_number = random.choice(target_list)
    open_box_list =  [x for x in target_list if (x != target) and (x != select_number)]
    open_box = random.choice(open_box_list)
    if change == True:
        select_number = random.choice([s for s in target_list if (s != select_number) and (s != open_box)])
    if select_number == target:
        return 1
    else:
        return 0

# nが変わると正解率がどう変化するか見てみる
change_accuracy_list = []
no_change_accuracy_list = []
x = []

for n in range(3, 101):
    change_result = []
    no_change_result = []
    x.append(n)
    for _ in range(1000):
        change_result.append(montihole_n(n, True))
    for _ in range(1000):
        no_change_result.append(montihole_n(n, False))

    change_hit = len(list(filter(lambda x:x == 1, change_result)))/len(change_result)*100
    no_change_hit = len(list(filter(lambda x:x == 1, no_change_result)))/len(no_change_result)*100
    change_accuracy_list.append(change_hit)
    no_change_accuracy_list.append(no_change_hit)

# グラフで描画
plt.figure()
sns.lineplot(x, change_accuracy_list, label='change')
sns.lineplot(x, no_change_accuracy_list, label='no_change')
plt.show()
```  
結果は...  
[![mohtyhall.png](https://i.postimg.cc/7ZxpRP3F/mohtyhall.png)](https://postimg.cc/nCPRjJw2)  
ということになり、ドアの数が少なければ明らかに当たりを引く確率に差がありますが、ドアが１０個くらいになる頃からその差はほとんど見られなくなるようです。  
少し、変化の大きい部分に注目してみてみます。  
[![montyhall-20.png](https://i.postimg.cc/VNHv6VsN/montyhall-20.png)](https://postimg.cc/1gws7Mqx)  
||3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|change|70.0|37.2|26.8|19.8|17.0|13.200000000000001|12.9|12.0|11.3|7.7|8.5|7.5|7.199999999999999|7.5|5.2|4.1000000000000005|6.6000000000000005|5.1|
|no_change|33.6|24.099999999999998|19.7|15.1|13.700000000000001|11.799999999999999|10.4|10.4|8.4|8.5|6.6000000000000005|7.3999999999999995|7.3999999999999995|6.4|5.8999999999999995|4.9|6.4|5.800000000000001|  
  
ドアの数を２０個までにしてみてみると、明らかに差を感じるのはドアの数が６個くらいまでで、12個以降では逆転することもあるほど差がなくなっています。 
  
# Ⅴ. 結論  
　今回、モンティ・ホール問題を今さらながら検証してみました。すでに当該ゲームにおいては、選択を変える方が当たりになる確率が高くなることは証明されていましたが、個人的な疑問であったドアの数を１００個で考えた方がわかりやすいのか？という点においては、ドアの数を増やすほどに確率の差異がなくなるため、どちらの方が当たりやすいかを考えることができなくなるだろうということがわかりました。  
 発展形として、ドアの数が増えたときに開放されるドアの数も増やしてみたり、選べるドアの数を増やすといったバリエーションでの検証もいずれしてみたいなと思いました。面白い確率バランスになるゲームになれば、令和のモンティ・ホール問題を新たに生み出せるかも！？  
  
　最後まで、雑文読んでいただきありがとうございます。過去に学者さんを巻き込んで物議を醸した問題も、Pythonの力を借りれば、私のような数学音痴でも検証ができる時代になりました。本職の方々でコーディングや可視化の手法など、改善点などあればご指摘いただけたら幸いです。