Think Bayes Note 2: Monty Hall 问题
Contents [show]
1. 问题描述
Monty Hall 是一个名为 Let’s Make a Deal 的电视节目的主持人,Monty Hall 问题 的描述为,假设你参加了一个游戏节目,面前有三扇关着的大门,其中一扇门后面有一辆汽车,另外两扇门后面则各有一头山羊,如果你能猜中哪扇门后有汽车,就可以赢得汽车作为奖品。
首先,你要先选择一扇门(记选择的门为门 A,另外两扇门为门 B 和门 C)。在打开这门 A 之前,为了增加悬念,主持人(知道哪扇门后面有汽车)会打开门 B 或 C 中的一扇没有汽车的门。然后,主持人会给你一个选择,你可以坚持最初的选择,或者更换选择另一扇未打开的门。问题是:你是否应该更换选择?更换选择是否有会带来区别?
2. 推导求解
从直觉的角度来看,最后要从两扇门中选一个,选中汽车的概率是 0.5,是否更换选择不会带来什么区别。但是,这个直觉并不正确,主持人打开一扇没有奖品的门这一行为,在一定程度上降低了结果的不确定性,有助于我们选中有汽车的门。
假设 HA、HB、HC 分别为汽车在门 A、B、C 后面,记事件 D 为主持人打开了门 B,且汽车没有在后面。整个问题分为初始选择门 A、主持人打开没有汽车的门 B、最终选择三个阶段,下面分阶段进行分析。
2.1. 初始选择门 A
在初始选择时,没有任何的额外信息,认为汽车在门 A、B、C 后面的概率相同,即:
P(HA)=P(HB)=P(HC)=13
2.2. 主持人打开没有汽车的门 B
如果 HA 为真(即汽车在门 A 后面),当主持人打开没有汽车的门时,主持人可以打开 B 或 C 任意一扇门,认为主持人打开 B 或 C 的可能性相同,此时事件 D 发生(主持人打开门 B,且汽车没有在后面)的概率为 12,即:
P(D|HA)=12
如果 HB 为真(即汽车在门 B 后面),当主持人打开没有汽车的门时,一定不会打开门 B,因为主持人只能选择打开没有汽车的门。此时事件 D 发生的概率为 0,即:
P(D|HB)=0
如果 HC 为真(即汽车在门 C 后面),当主持人打开没有汽车的门时,只能打开门 B,因为门 A 被玩家选了,门 C 后面有汽车。此时事件 D 发生的概率为 1,即:
P(D|HC)=1
2.3. 最终选择
要决定是否更换选择,需要计算 HA、HB 和 HC 的后验概率 P(HA|D)、P(HB|D) 和 P(HC|D)。要使用贝叶斯公式计算后验概率,还需要求得 P(D),由全概率公式以及前面式 (1)、 (2)、 (3)、 (4) 的结果,有:
P(D)=P(HA)P(D|HA)+P(HB)P(D|HB)+P(HC)P(D|HC)=13×12+13×0+13×1=12
于是可得各后验概率为:
P(HA|D)=P(HA)P(D|HA)P(D)=13×1212=12
P(HB|D)=P(HB)P(D|HB)P(D)=13×012=0
P(HC|D)=P(HC)P(D|HC)P(D)=13×112=23
可见,此时坚持选择门 A 有 13 的概率选中汽车,而更换选择到门 C 则具有 13 的概率选中汽车,更换选择可以提高选中汽车的概率。
3. 代码求解
下面使用代码来求解此问题。定义 Monty
类如下:
class Monty(Pmf): def likelihood(self, data, hypo): if hypo == data: return 0 elif hypo == 'A': return 0.5 else: return 1 def update(self, data): for hypo in self.values(): like = self.likelihood(data, hypo) self.mult(hypo, like) self.normalize()
注意其中用于计算似然度的 likelihood()
方法:参数 data
为主持人打开的门,hypo
为假设汽车所在的门。如果 hypo == data
,则说明主持人打开了汽车所在的门,这一事件不可能发生,即主持人打开 data
门的概率为 0;如果 hypo == 'A'
,即玩家初次就选中了有汽车的门,此时主持人可以任意打开 B 和 C 中的一个,主持人打开 data
门的概率为 0.5;如果玩家初次没有选中有汽车的门,那么主持人只能打开剩下的两扇门中没有汽车的那扇,如果此时还有 hypo
不等于 data
,即汽车不在 data
门后,则主持人只打开 data
门的概率为 1。
调用代码为:
hypos = 'ABC' monty = Monty(hypos) monty.update('B') monty.print()
输出为:
prob value A 0.333333 B 0.000000 C 0.666667
Monty 类其实实现了一套计算后验概率的基础流程,先计算似然度,然后根据新获得的数据计算后验概率。可以将这一过程抽象为一个单独的类 Suite
:
class Suite(Pmf): def likelihood(self, data, hypo): raise UnimplementedMethodException() def update(self, data): for hypo in self.values(): like = self.likelihood(data, hypo) self.mult(hypo, like) return self.normalize()
其中 likelihood()
为一个抽象方法,由表示具体问题的子类来实现,计算后验概率的 update()
方法流程固定,由 Suite
实现。Monty Hall 问题使用 Suite
的实现为 MontySuite
:
class MontySuite(Suite): def likelihood(self, data, hypo): if hypo == data: return 0 elif hypo == 'A': return 0.5 else: return 1
使用方法和先前一样:
hypos = 'ABC' monty_suite = MontySuite(hypos) monty_suite.update('B') monty_suite.print()
输出为:
prob value A 0.333333 B 0.000000 C 0.666667
4. 一个变形
该问题可以变形为,假设主持人在打开没有汽车的门时,始终优先选择门 B,只有在迫不得已时(汽车在门 B 后面)才选择门 C。
此时先验概率不变,都是 13。而在主持人打开没有汽车的门时,如果 HA 为真,则主持人一定会打开门 B,有 P(D|HA)=1;如果 HB 为真,则主持人一定会打开门 C,有 P(D|HB)=0;如果 HC 为真,则主持人一定会打开门 B,有 P(D|HC)=1。再计算后验概率,可以得到
P(HA|D)=12P(HB|D)=0P(HC|D)=12
可见如果主持人打开了门 B,则汽车仍等可能地位于门 A 或门 C 后面,玩家是否更换选择没有影响。而如果主持人打开了门 C,则可以知道汽车一定在门 B 后面,玩家更换选择门 B 一定会选中汽车。