最初看到這個問題是初中的時候買了一本有關數學謎題的書裏面機率論的一張的課後拓展就是說到三門問題,當時做爲一個擴展閱讀看了一下,裏面說到了一個世界智商最高的女人秒殺了美國一大羣的數學高材生的精彩故事(比較誇張),當時對這個問題也是似懂非懂。html
蒙提霍爾問題,亦稱爲蒙特霍問題或三門問題(英文:Monty Hall problem),是一個源自博弈論的數學遊戲問題,大體出自美國的電視遊戲節目Let's Make a Deal。問題的名字來自該節目的主持人蒙提·霍爾(Monty Hall)。python
最初的表述是:編程
參賽者會看見三扇關閉了的門,其中一扇的後面有一輛汽車,選中後面有車的那扇門就能夠贏得該汽車,而另外兩扇門後面則各藏有一隻山羊。當參賽者選定了一扇門,但未去開啓它的時候,節目主持人開啓剩下兩扇門的其中一扇,露出其中一隻山羊。主持人其後會問參賽者要不要換另外一扇仍然關上的門。
問題是:換另外一扇門會否增長參賽者贏得汽車的機會率?app
這個古老的問題一經提出就引發了劇烈的爭論,有人認爲換與不換最終獲得車的機率都是\(\frac{1}{2}\),有人認爲換門以後獲得車的機率更大,應該選擇換門以後獲得車的機率爲\(\frac{2}{3}\)在撰寫這篇文章的時候在果殼上還有人在爲此爭吵,知乎上也有許多關於這方面的討論,其實這些爭論不少狀況下都是因這個問題的模糊表述所引發的,關鍵點在於主持人對於門後的狀況是否瞭解:dom
爲了後續的討論,這裏採用維基百科上對於這一個問題的不含糊的定義ide
嚴格的表述以下:post
那麼這個問題這能夠很好的理解了,引用維基的一幅圖片解析:
spa
有三種可能的狀況,所有都有相等的可能性(\(\frac{1}{3}\)):日誌
因此玩家選擇換門以後獲勝的機率應爲\(\frac{2}{3}\)code
定義:
事件A
爲一開始玩家選擇的一扇門事件H
爲最後門後的結果
若是是選擇不換門的策略
$P \left(H=car \right) = P \left(A=car \right) = \frac{1}{3} $
由於選擇的是不交換的策略,全部只有一開始選中的是汽車,最後才能選中汽車。
選擇交換門的策略
$P \left(H=car \right) = P \left(A=sheep \right) = \frac{2}{3} $
由於選擇的是交換的策略,全部只有一開始選中的是羊,最後才能選中汽車。
實踐是檢驗真理的惟一標準,在流言終結者看到他們人工重複這個實驗區驗證,發現這樣很浪費時間。何經過計算機去去模擬這一段過程呢?
下面使用python程序來模擬這一段過程:
from __future__ import division import logging from matplotlib import pyplot as plt import numpy as np import random class MontyHall(object): """docstring for MontyHall""" def __init__(self, num=3): """ 建立一個door列表 0 表明關門 1 表示後面有車 -1 表明門被打開 """ super(MontyHall, self).__init__() self.doors = [0] * num self.doors[0] = 1 self.choice = -1 self.exclude_car = False self.shuffle() def shuffle(self): """ 開始新遊戲 從新分配門後的東西 """ if self.exclude_car == True: self.doors[0] = 1 self.exclude_car = False for i in xrange(len(self.doors)): if self.doors[i] == -1: self.doors[i] = 0 random.shuffle(self.doors) def make_choice(self): """ player隨機選擇一扇門 """ self.choice = random.randint(0, len(self.doors) - 1) logging.info("choice: %d" % self.choice) logging.info("original: %s" % self.doors) def exclude_doors(self): """ 主持人知道門後的狀況排除門 直到剩餘兩扇門 """ to_be_excluded = [] for i in xrange(len(self.doors)): if self.doors[i] == 0 and self.choice != i: to_be_excluded.append(i) random.shuffle(to_be_excluded) for i in xrange(len(self.doors) - 2): self.doors[to_be_excluded[i]] = -1 logging.info("final: %s" % self.doors) def random_exclude_doors(self): """ 主持人並不知道門後面的狀況隨機的開門 直到剩餘兩扇門 """ to_be_excluded = [] for i in xrange(len(self.doors)): if self.doors[i] != -1 and i != self.choice: to_be_excluded.append(i) random.shuffle(to_be_excluded) for i in xrange(len(self.doors) - 2): if self.doors[to_be_excluded[i]] == 1: self.exclude_car = True self.doors[to_be_excluded[i]] = -1 logging.info("final: %s" % self.doors) def change_choice(self): """ player改變選擇 """ to_change = [] for i in xrange(len(self.doors)): if self.doors[i] != -1 and i != self.choice: to_change.append(i) self.choice = random.choice(to_change) logging.info("choice changed: %d" % self.choice) def random_choice(self): """ player 第二次隨機選擇門 """ to_select = [] for i in xrange(len(self.doors)): if self.doors[i] != -1: to_select.append(i) self.choice = random.choice(to_select) logging.info("random choice : %d" % self.choice) def show_answer(self): """ 展現門後的狀況 """ logging.info(self.doors) def check_result(self): """ 驗證結果 """ got_it = False if self.doors[self.choice] == 1: got_it = True return got_it
def unchange_choice_test(n): """ 不改變初始的選擇 """ result = {} game = MontyHall() for i in xrange(n): game.shuffle() game.make_choice() game.exclude_doors() if game.check_result(): result["yes"] = result.get("yes", 0) + 1 else: result["no"] = result.get("no", 0) + 1 for key in result: print "%s: %d" % (key, result[key]) return result["yes"] / n if __name__ == '__main__': logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.WARNING) results = [] test_num = 1000 round_num = 1000 for x in xrange(0,round_num): results.append(change_random_test(test_num) ) y_mean = np.mean(results) y_std = np.std(results) x = range(0,round_num) y = results plt.figure(figsize=(8,4)) plt.xlabel("round") plt.ylabel("frequency") plt.title("The frequency of the success") tx = round_num / 2 ty = y_mean label_var = "$\sigma \left( X \\right)=$%f" % y_std label_mean = "$ X =$%f" % y_mean p1_label = "%s and %s" % (label_var,label_mean) p1 = plt.plot(x,y,"-",label=p1_label,linewidth=2) plt.legend(loc='upper left') pl2 = plt.figure(2) plt.figure(2) plt.hist(results,40,normed=1,alpha=0.8) plt.show()
結果:
機率分佈:
成功的機率均值在 \(\frac{1}{3}\) 附近
def change_choice_test(n): """ 交換選擇的門 """ result = {} game = MontyHall() for i in xrange(n): game.shuffle() game.make_choice() game.exclude_doors() game.change_choice() if game.check_result(): result["yes"] = result.get("yes", 0) + 1 else: result["no"] = result.get("no", 0) + 1 for key in result: print "%s: %d" % (key, result[key]) return result["yes"] / n
一樣的方法繪圖獲得結果:
機率分佈:
成功的機率均值在 \(\frac{2}{3}\) 附近
經過上面的分析與模擬可知最佳的策略固然就是換門。
這種狀況下,主持人打開48扇都是羊的門後,再給你選擇,不少人這個時候應該就不會固守那\(\frac{1}{2}\),而會選擇換門
把門的數據增大到100,1000,這種狀況會更加明顯。
仍是經過一段程序模擬說明:
def change_choice_test_large(n,m): """ 交換選擇的門 """ result = {} game = MontyHall(m) for i in xrange(n): game.shuffle() game.make_choice() game.exclude_doors() game.change_choice() if game.check_result(): result["yes"] = result.get("yes", 0) + 1 else: result["no"] = result.get("no", 0) + 1 for key in result: print "%s: %d" % (key, result[key]) return result["yes"] / n if __name__ == '__main__': logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.WARNING) results = [] test_num = 1000 round_num = 1000 for x in xrange(0,round_num): results.append(change_choice_test_large(test_num,50) )
結果:
這時候就要選擇交換門。
這是第3種策略,成功的機率和硬幣有關,也就是\(\frac1 2\),這種狀況就是從剩下的門中隨機選擇一扇,這個策略從上面分析來看不是最好的,可是比不改變的策略要好。
程序的模擬結果:
這種狀況下其實就是一個條件機率,事件A是玩家最後開到的是車,事件B是主持人打開的門是羊。
\[ P(A|B) = \dfrac{P(B|A) \cdot P(A) }{P(B)} \]
由於只有主持人開到是羊的狀況下,玩家纔有可能開到車因此 \(P(B|A) = 1\)
設玩家第一次選擇的門爲事件C
則
\[ P(A) = P(C='汽車') = \frac{1}{3} \]
\[ P(A|B) = \dfrac{P(A) }{P(B) } = \dfrac{\frac{1}{3}}{\frac{2}{3}}= \frac{1}{2} \]
\[ P(A) = P(C='羊') \times \frac{1}{2} = \frac{1}{3} \]
\[ P(A|B) = \dfrac{P(A) }{P(B) } = \dfrac{\frac{1}{3}}{\frac{2}{3}}= \frac{1}{2} \]
所以在主持人不知道門後的狀況下打開一扇,而後發現門後是羊的狀況下,換門與不換門最終的機率都是\(\frac{1}{2}\)
仍是能夠經過程序進行模擬:
def unknown_doors_choice_test(n): """ 主持人並不知道門後面的狀況隨機的開門 交換選擇的門 """ result = {} game = MontyHall() continue_count = 0 for i in xrange(n): game.shuffle() game.make_choice() game.random_exclude_doors() game.change_choice() if game.exclude_car == False: continue_count += 1 if game.check_result(): result["yes"] = result.get("yes", 0) + 1 else: result["no"] = result.get("no", 0) + 1 #for key in result: # print "%s: %d" % (key, result[key]) logging.info("continue_count: %d" % continue_count) if continue_count == 0: return 0.0 return result["yes"] / continue_count
在這種狀況下交換門也沒有提高成功的機率
今天寫的這篇東西也算是瞭解我童年的一個遺憾,人的直覺有時候是很不可靠,要擺脫我的侷限的認知才能擁抱更大的世界。
什麼?看完這些解析,你還以爲不滿意那麼你還能夠從下面的參考中尋找更好的解析,本文撰寫過程有部分的圖片引用自一下的參考,若是你還有疑問歡迎你聯繫我進一步的討論。
下面是三門問題的兩個翻版,引用自三門問題及相關:
你結交一位新朋友,問她是否有孩子。她說有,有兩個。你問,有女孩嗎?她說有。那麼,兩個都是女孩的機率是多少?
答:三分之一。由於生兩個孩子的可能性有四種等可能:BB、GG、BG、GB(即男男、女女、男女、女男)。 由於咱們已知至少有一個女兒,因此BB是不可能的。所以GG是可能出現的三個等可能的結果之一,因此兩個孩子都是女兒的機率爲三分之一。這對應了三門問題的第一種狀況。
你結交一位新朋友,問她是否有孩子。她說有,有兩個。你問,有女孩嗎?她說有。次日,你看見她帶了一個小女孩。你問她,這是你女兒嗎?她說,是。她的兩個孩子都是女孩的機率是多少?
這個機率和生女孩的機率相同,二分之一。這彷佛很是奇怪,由於咱們所擁有的信息看起來並不比第一種狀況時多,但機率卻不一樣。可是這裏的問題實際上是,那個你沒>見過的孩子是女孩的機率是多少?這個機率和生女孩的機率相同,二分之一。
這對應了三門問題的第二種狀況。固然這裏也有語言問題,必須假定這位母親不是特定帶出一個小女孩來給你看的。也就是說你只是碰巧發現了它是位小女孩。這取決因而判斷選擇 或q 隨機選擇。若是是被你碰巧撞見這是屬於隨機選擇。這就對應了三門問題的第二種狀況。這實際上是增長了信息的。不然若是她主動帶一個小女孩過來給你,則屬於判斷選擇。
你獲得的答案依賴於所講的故事;它依賴於你是如何得知至少一個孩子是女孩的。
亞當、比爾和查爾斯被關在一個監獄裏,只有監獄看守知道誰會被判死刑,另外兩位將會獲釋。有1/3的機率會被處死刑的亞當,給他母親寫了一封信,想要獲釋的比爾或查爾斯幫忙代寄。當亞當問看守他應當把他的信交給比爾仍是查爾斯時,這位富有同情心的看守很爲難。他認爲若是他把將要獲釋的人的名字告訴亞當,那麼亞當就會有1/2的機率被判死刑,由於剩下的人和亞當這兩人中必定有一我的被處死。若是他隱瞞這信息,亞當被處死的機率是1/3。既然亞當知道其餘兩人中必有一人會獲釋,那麼亞當本身被處死的機率怎麼可能會由於看守告訴他其餘兩人中被獲釋者的姓名後而改變呢?
正確的答案是:看守不用小心,由於即便把獲釋人的姓名告訴亞當,亞當被處死的機率仍然是1/3,沒有改變。可是,剩下的那位沒被點名的人就有2/3的機率被處死(被處死的可能性升高了)。若是這個問題換一種說法,就是看守無心間說出了查爾斯不會死。那麼機率就會發生改變。
這個其實和三門問題是一致的。你能夠把獄卒當成主持人,被處死當成是大獎,那麼這個是對應於三門問題的第一種狀況,就是主持人知道門後面的狀況。獄卒說出誰會被釋放,至關於主持人打開一扇門。可是由於三囚徒問題不能選擇,也就至關於三門問題中的不換門的策略。最終的機率仍是1/3是沒有發生改變的。
爲了不產生歧義,規定一下:
1.若是(亞當,查爾斯)被釋放,那麼獄卒會告訴亞當:"查爾斯被釋放"。
2.若是(亞當,比爾)被釋放,那麼獄卒會告訴亞當:"比爾被釋放"
3.若是(查爾斯,比爾)被釋放,那麼獄卒會以1/2的機率告訴亞當:"查爾斯被釋放"或者"比爾被釋放"
意思就很明顯了,在獄卒說出比爾被釋放的條件下,亞當被釋放的機率是?用條件機率算一下。
定義事件:
A :獄卒說出"比爾被釋放"
B :表明亞當被釋放。
\[ P(A) = \frac{1}{2} \]
\[ P(A \cap B) = \frac{1}{3} \]
\[ P(B|A)=\frac{P(A \cap B)}{P(A)}= \frac{2}{3} \]
那何時纔是1/2的機率呢?
規則3更改成:若是(查爾斯,比爾)被釋放,那麼獄卒會告訴亞當"比爾被釋放"
這個時候計算就是: \[ P(B|A)=\frac{P(A \cap B)}{P(A)}= \frac{\frac{1}{3}}{\frac{2}{3}} =\frac{1}{2} \]
那若是規則3改成:若是(查爾斯,比爾)被釋放,那麼獄卒會告訴亞當"查爾斯被釋放"
這個時候:亞當被釋放的機率就會變爲1
問題在於規則2和規則3下說"比爾被釋放"不是等機率發生的。
the end.
更新日誌: