Think Bayes Note 2: Monty Hall 问题
1. 问题描述
Monty Hall 是一个名为 Let’s Make a Deal 的电视节目的主持人,Monty Hall 问题 的描述为,假设你参加了一个游戏节目,面前有三扇关着的大门,其中一扇门后面有一辆汽车,另外两扇门后面则各有一头山羊,如果你能猜中哪扇门后有汽车,就可以赢得汽车作为奖品。
首先,你要先选择一扇门(记选择的门为门 A,另外两扇门为门 B 和门 C)。在打开这门 A 之前,为了增加悬念,主持人(知道哪扇门后面有汽车)会打开门 B 或 C 中的一扇没有汽车的门。然后,主持人会给你一个选择,你可以坚持最初的选择,或者更换选择另一扇未打开的门。问题是:你是否应该更换选择?更换选择是否有会带来区别?
2. 推导求解
从直觉的角度来看,最后要从两扇门中选一个,选中汽车的概率是 0.5,是否更换选择不会带来什么区别。但是,这个直觉并不正确,主持人打开一扇没有奖品的门这一行为,在一定程度上降低了结果的不确定性,有助于我们选中有汽车的门。
假设 $H_A$、$H_B$、$H_C$ 分别为汽车在门 A、B、C 后面,记事件 D 为主持人打开了门 B,且汽车没有在后面。整个问题分为初始选择门 A、主持人打开没有汽车的门 B、最终选择三个阶段,下面分阶段进行分析。
2.1. 初始选择门 A
在初始选择时,没有任何的额外信息,认为汽车在门 A、B、C 后面的概率相同,即:
\begin{equation}
P(H_A) = P(H_B) = P(H_C) = \frac{1}{3} \tag{1}
\end{equation}
2.2. 主持人打开没有汽车的门 B
如果 $H_A$ 为真(即汽车在门 A 后面),当主持人打开没有汽车的门时,主持人可以打开 B 或 C 任意一扇门,认为主持人打开 B 或 C 的可能性相同,此时事件 D 发生(主持人打开门 B,且汽车没有在后面)的概率为 $\frac{1}{2}$,即:
\begin{equation}
P(D|H_A) = \frac{1}{2} \tag{2}
\end{equation}
如果 $H_B$ 为真(即汽车在门 B 后面),当主持人打开没有汽车的门时,一定不会打开门 B,因为主持人只能选择打开没有汽车的门。此时事件 D 发生的概率为 0,即:
\begin{equation}
P(D|H_B) = 0 \tag{3}
\end{equation}
如果 $H_C$ 为真(即汽车在门 C 后面),当主持人打开没有汽车的门时,只能打开门 B,因为门 A 被玩家选了,门 C 后面有汽车。此时事件 D 发生的概率为 1,即:
\begin{equation}
P(D|H_C) = 1 \tag{4}
\end{equation}
2.3. 最终选择
要决定是否更换选择,需要计算 $H_A$、$H_B$ 和 $H_C$ 的后验概率 $P(H_A|D)$、$P(H_B|D)$ 和 $P(H_C|D)$。要使用贝叶斯公式计算后验概率,还需要求得 $P(D)$,由全概率公式以及前面式 (1)、 (2)、 (3)、 (4) 的结果,有:
\begin{align}
P(D) &= P(H_A)P(D|H_A) + P(H_B)P(D|H_B) +P(H_C)P(D|H_C) \\
&= \frac{1}{3} \times \frac{1}{2} + \frac{1}{3} \times 0 + \frac{1}{3} \times 1 = \frac{1}{2} \tag{5}
\end{align}
于是可得各后验概率为:
\begin{equation}
P(H_A|D) = \frac{P(H_A)P(D|H_A)}{P(D)} = \frac{\frac{1}{3} \times \frac{1}{2}}{\frac{1}{2}} = \frac{1}{2} \tag{6}
\end{equation}
\begin{equation}
P(H_B|D) = \frac{P(H_B)P(D|H_B)}{P(D)} = \frac{\frac{1}{3} \times 0}{\frac{1}{2}} = 0 \tag{7}
\end{equation}
\begin{equation}
P(H_C|D) = \frac{P(H_C)P(D|H_C)}{P(D)} = \frac{\frac{1}{3} \times 1}{\frac{1}{2}} = \frac{2}{3} \tag{8}
\end{equation}
可见,此时坚持选择门 A 有 $\frac{1}{3}$ 的概率选中汽车,而更换选择到门 C 则具有 $\frac{1}{3}$ 的概率选中汽车,更换选择可以提高选中汽车的概率。
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。
此时先验概率不变,都是 $\frac{1}{3}$。而在主持人打开没有汽车的门时,如果 $H_A$ 为真,则主持人一定会打开门 B,有 $P(D|H_A) = 1$;如果 $H_B$ 为真,则主持人一定会打开门 C,有 $P(D|H_B) = 0$;如果 $H_C$ 为真,则主持人一定会打开门 B,有 $P(D|H_C) = 1$。再计算后验概率,可以得到
\begin{equation}
P(H_A|D) = \frac{1}{2} \\
P(H_B|D) = 0 \\
P(H_C|D) = \frac{1}{2} \\
\end{equation}
可见如果主持人打开了门 B,则汽车仍等可能地位于门 A 或门 C 后面,玩家是否更换选择没有影响。而如果主持人打开了门 C,则可以知道汽车一定在门 B 后面,玩家更换选择门 B 一定会选中汽车。