最初看到这个问题是初中的时候买了一本有关数学谜题的书里面几率论的一张的课后拓展就是说到三门问题,当时做为一个扩展阅读看了一下,里面说到了一个世界智商最高的女人秒杀了美国一大群的数学高材生的精彩故事(比较夸张),当时对这个问题也是似懂非懂。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.
更新日志: