读到一篇名为《和上帝一起掷骰子》的文章,里面提到不少反直觉的概率问题,好些算出来的结果和第一印象大相径庭。今天挑几个有意思的例子,一起看看直觉和数学的概率到底差多远。
先看第一个:
假如 1000 人中有 1 人携带 X 病毒,有一种检测能 100% 检出感染者,但对未感染的人有 5% 的误报率。现在随机找一个人,检测结果阳性——也就是说报告他为携带者。那么,这个人真的携带病毒的可能性有多大?
这里我们暂时忽略各种外在条件。看起来 5% 的误检率已经很低了,可事实上,此人真正感染的概率只有 1.96%。
计算很简单:
$$
\frac{1}{999 \times 5\% + 1}
$$
哪怕让他连续检测两次都呈阳性,实际患病的概率也不过:
$$
\frac{1}{999 \times 5\% \times 5\% + 1} \approx 28.6\%
$$
所以在现实中,初筛阳性后通常必须复检,目的就是尽可能排除假阳性。
再看另一个例子:
雨夜,一辆出租车肇事。一位目击者说「车是蓝色的」。已知在当时的环境下,这位证人正确区分蓝色和绿色的准确率是 80%;而当地 85% 的出租车是绿色,15% 是蓝色。看上去眼见为实,八成总不该错吧?可那辆车真的是蓝色的概率,算下来只有 41.38%。
$$
\frac{15\% \times 80\%}{85\% \times 20\% + 15\% \times 80\%}
$$
最后这个,是我觉得最有意思的一个问题:
有一个人,有两个孩子。已知其中一个孩子是男孩,且这个男孩的生日是星期二。问另一个孩子也是男孩的概率是多少?
直觉上我们很容易想:生男生女不都是 1/2 吗?跟星期几有什么关系?可答案是 13/27。
你可能会觉得离谱。为了验证,我写了一段 Python 程序来模拟这个场景:
one_tuesday_boy = 0
one_tuesday_boy_plus_another_boy = 0
for gender1 in ['m', 'f']:
for birth1 in range(1, 8):
for gender2 in ['m', 'f']:
for birth2 in range(1, 8):
if (gender1 == 'm' and birth1 == 2) or (gender2 == 'm' and birth2 == 2):
one_tuesday_boy += 1
if gender1 == 'm' and gender2 == 'm':
one_tuesday_boy_plus_another_boy += 1
print one_tuesday_boy_plus_another_boy, '/', one_tuesday_boy
假设生男生女和一周七天出生的概率均等,那么总共就有 2×7×2×7 = 196 种等可能的情况。通过程序枚举,满足「有一个周二出生的男孩」的情况是 27 种,其中两个都是男孩的有 13 种。答案是直接暴力跑出来的。
概率问题就是这样,稍不注意就会被直觉带偏。在云栈社区,你也可以找到更多关于 Python 和算法的硬核讨论,欢迎随时来转转。