モンティ・ホール問題は「主観的な答えと確率論にのっとった答えが一致しない」という不思議な問題です。今回はこの「モンティ・ホール問題」の簡単なシミュレーションプログラムを書いてみました。経験主義万歳!
import random
def monty_hall():
# 0,1,2の扉からランダムに正解が選ばれる
answer = random.randrange(3)
# 解答者は0,1,2から好きな扉を選ぶ
first_choice = random.randrange(3)
# 司会者であるモンティははずれの扉をひとつ開く
monty_choice = random.choice(tuple({0, 1, 2} - {answer, first_choice}))
# 解答者は2回目の選択として、最初に選んだ扉とは違う扉を選択する
second_choice = ({0, 1, 2} - {first_choice, monty_choice}).pop()
# 2回目に選んだ扉は正解なのか?
return answer == second_choice
if __name__ == '__main__':
for x in (10, 100, 1000, 100000):
# x回の試行中、monty_hall()がTrueを返した回数を記録する。
win = sum(1 for _ in range(x) if monty_hall())
print("試行回数{0}回のときの確率 : {1}".format(x, win / x))
# 試行回数10回のときの確率 : 0.7
# 試行回数100回のときの確率 : 0.58
# 試行回数1000回のときの確率 : 0.673
# 試行回数100000回のときの確率 : 0.66657
「モンティ・ホール問題」最大の論点は「司会者がはずれの扉を見せた後、挑戦者は最初の選択を変えるべきか」というところにありますが、「変えたほうが正解である確率が高い」ということが確かめられました。
ちなみに上記のコードはわかりやすいよう、やや冗長な書き方をしていますが、次のようにリファクタリングすることもできます。
def refactoring_month_hall():
# 0,1,2の扉からランダムに正解が選ばれる
answer = random.randrange(3)
# 解答者は0,1,2の扉から好きなものを選ぶ
first_choice = random.randrange(3)
# 最初に選んだ扉が正解ではない => もう一つの扉が正解
return answer != first_choice
if __name__ == '__main__':
for x in (10, 100, 1000, 10000, 100000):
win = sum(1 for _ in range(x) if refactoring_month_hall())
print("試行回数{0}回のときの確率 : {1}".format(x, win / x))
# 試行回数10回のときの確率 : 0.8
# 試行回数100回のときの確率 : 0.65
# 試行回数1000回のときの確率 : 0.678
# 試行回数10000回のときの確率 : 0.6676
# 試行回数100000回のときの確率 : 0.66585
こちらでも「最初の選択ではない扉をえらぶほうがよい」ということがはっきりわかります。不思議ですね(´・ω・`)