上一篇:(五)验证很快,找到很难——讲有些事能算但算不动。 这一篇:讲世界是不确定的,而概率是唯一能驾驭不确定性的工具。

耗时:读完约 50 分钟,动手约 2 小时。


开头:一个检测,准确率 99%,测出阳性,你慌不慌

假设你去做一项体检,医生说:

这个检测准确率 99%。

结果出来:阳性。

你觉得自己有病的概率是多少?99%?90%?

正确答案:可能不到 10%。

这不是抬杠。这是一个真实的、反复被证实的数学事实。而它之所以反复骗到人,是因为它踩中了人类直觉的一个盲区——我们把"检测准确率"和"我有病"混为一谈了。

这一篇就从这里讲起。前面五篇都在讲"确定的东西"——格点、离散、证明、可计算、复杂度。但真实世界里,大多数判断是在不确定下做的:体检、风控、垃圾邮件、天气预报、抽卡、推荐系统、AI 的每一步。

概率论,是计算机科学里唯一能处理"不确定"的数学。 而且它有一个反直觉到骨子里的特性:用随机,反而能算得更准、更快。


一、贝叶斯定理:把"直觉"翻译成"公式"

先说那个检测。关键是要区分三个概念,大多数人只听过一个:

概念问什么例子
敏感性(真阳性率)真有病的人,测出阳性的概率99%
特异性(真阴性率)没病的人,测出阴性的概率99%
患病率(先验)随机一个人有病的概率0.1%

“准确率 99%“这句话,什么都没说清楚。 它可能是敏感性 99%、特异性 99%,也可能只是其中一个。而结论完全取决于这三个数怎么组合。

贝叶斯定理一句话

阳性后真有病的概率(PPV)= 真阳性 ÷ 阳性总数

写成公式(这就是贝叶斯定理):

PPV = 患病率 × 敏感性 ÷ [患病率 × 敏感性 + (1−患病率) × (1−特异性)]

实测:10 万人模拟

我模拟了 10 万人(患病率 0.1%,敏感性 99%,特异性 99%):

真病人    100 人
健康人  99,900 人
真阳性 TP = 99 人        ← 100 个病人,99 个被查出
假阳性 FP = 999 人       ← 99,900 个健康人,1% 被误判 = 999 人
阳性总数 = 1,098 人
阳性中真有病 = 99 ÷ 1,098 = 9.02%

你测出阳性,真有病的概率是 9.02%。

为什么这么低?因为假阳性的人数(999)是真阳性人数(99)的 10 倍。

  • 病很罕见(0.1%),所以绝大多数受检者是健康人
  • 健康人里 1% 被误判 → 数量巨大
  • 病人里 99% 被查出 → 但病人本来就少

“准确率 99%“掩盖了"健康人太多了"这个事实。

患病率一换,结论天翻地覆

同一个检测(敏感性 99%、特异性 99%),换不同的患病率:

患病率阳性后真有病
0.1%9.02%
0.5%33.22%
1.0%50.00%
5.0%83.90%
10.0%91.67%
30.0%97.70%

同样的检测,同样的 99%,在罕见病上是 9%,在常见病上是 97%。

这就是贝叶斯定理最核心的一课:结论不只取决于"检测多准”,更取决于"这件事本来就多常见”。

特异性动一点点,结论翻五倍

再看一个反直觉的:

特异性 99%   → PPV = 9.02%
特异性 99.9% → PPV = 49.77%

特异性只提高 0.9 个百分点,PPV 从 9% 跳到 50%。

因为假阳性的人数直接除以 10,而假阳性正是压垮 PPV 的那部分。

为什么"准确率"这个词在医学和风控里几乎没用? 因为它把敏感性和特异性混成一个数。而这两个数对结论的影响,一个在分子、一个在分母,方向完全不同。


二、条件概率的陷阱:先验比你想的重要

贝叶斯定理逼你面对一个不舒服的事实:你的判断,取决于你先相信什么(先验)。

这不是"主观”,这是数学结构。换一种说法就更刺人:

说法 A:"这个检测准确率 99%"
说法 B:"这个检测的假阳性率是 1%"

这两句话是同一件事。 但 A 让你觉得"很可靠”,B 让你开始警惕。

而真正该问的是第三个:“这件事本身有多常见?” —— 先验。没有它,前两句话都不完整。

计算机里的贝叶斯无处不在:

  • 垃圾邮件过滤器(贝叶斯分类器)—— 一个词出现在垃圾邮件里的概率,要乘以"垃圾邮件本身的占比"
  • 推荐系统 —— “你喜欢这个” 要乘以 “你本来就喜欢这类东西”
  • 异常检测 —— “这个行为像攻击” 要乘以 “攻击本来就很罕见”(否则整天误报)

三、用随机,反而更快更准:随机化算法

前面是"用概率理解世界"。现在反过来:用概率当工具。

这是概率论最反直觉的应用——故意引入随机性,让算法变得更好。

随机快排:治"最坏情况"

快速排序有个臭名昭著的问题:输入已经有序时,它会退化。

实测(输入已经是升序排列):

n确定性快排(取第一个为基准)随机化快排(随机选基准)
3005.5 ms0.7 ms
60019.5 ms1.7 ms
100041.8 ms1.7 ms

同样的问题,随机选基准,快了 20 倍以上。

为什么?确定性快排选固定位置当基准,敌人(或者巧合)可以构造出最坏输入。随机化快排随机选基准——不存在一个"最坏输入",因为输入不知道你会选谁。

这是随机化的第一课:它把"最坏情况"从"输入能控制的"变成"纯运气"。 运气可以被分析(期望值),敌意不能。

Miller-Rabin:用"可能"换"肯定"

判断一个大数是不是素数。确定性方法(试除法)要试到 √n 次;n 一大就完蛋。

Miller-Rabin 是一个概率算法:它不保证 100% 正确,但错误概率可以压到任意小(比如 10⁻³⁰)。

实测:

数试除法Miller-Rabin
1,000,0030.15 ms0.04 ms
1,000,000,0074.61 ms0.05 ms
1,000,000,000,039189.33 ms0.12 ms
2¹²⁷−1(39 位)不可行(要试 1.3×10¹⁹ 次)0.7 ms

2¹²⁷−1 这个数,试除法宇宙终结都试不完,Miller-Rabin 半毫秒给出"素数",且错误概率小于十亿分之一。

这是随机化的第二课:用一点点"可能错"的代价,换取"肯定算不动"变成"瞬间算完"。 而"可能错"这个代价,可以压到比你被雷劈还小的概率。

蒙特卡洛:用随机算 π

最纯粹的例子。π 是个确定的东西,但用随机能算它:

往正方形里撒点,落在内切圆里的比例,乘 4 就是 π 的估计。

点数π 估计误差
1,0003.1400000.0016
10,0003.1528000.0112
100,0003.1452000.0036
1,000,0003.1386360.0030
10,000,0003.1418390.0002

撒点撒得越多,越准。 但注意收敛速度:

误差按 1/√n 缩小。想精确 10 倍,需要 100 倍的点数。

这就是蒙特卡洛方法的代价:它永远到不了"精确",但能到"足够好",而且对任何问题都通用。 高维积分、粒子物理、金融风险、AI 里的采样——全是它。


四、三个反直觉概率题(全都实测过)

1. 三门问题:换门,赢率翻倍

你面前三扇门,一扇后面是车,两扇是羊。你选一扇,主持人打开另外两扇中的一扇(一定是羊),问你:换不换?

直觉:剩下两扇,一半一半,换不换都行。错。

实测 20 万次:

不换:赢 33.26%
换:  赢 66.74%

换门,赢率翻倍。

为什么?你第一次选对的概率是 1/3。主持人开一扇羊门,没有改变"你最初那扇门是 1/3"这个事实——他开门这件事,把剩下的 2/3 概率集中到了那一扇没开的门上。

关键:主持人的动作不是随机的,他"必须开一扇羊门"。这个信息改变了概率。

2. 生日悖论:23 人就有一半概率撞

10 人 → 11.8%
20 人 → 41.0%
23 人 → 51.4%   ← 过半
30 人 → 70.5%
50 人 → 97.0%

23 个人里,有两个人同一天生日的概率超过一半。 直觉上觉得要 100 多人才行。

原因是第二篇讲过的:你要比的是所有配对(C(23,2)=253 对),不是"某个人和我同一天"。

3. 抽卡:1% 出率,抽 100 次,出卡率只有 63%

抽 10 次 → 9.5%
抽 50 次 → 39.4%
抽 100 次 → 63.5%   ← 不是 100%!
抽 300 次 → 95.0%

1% 出率,抽 100 次,至少出一次的概率只有 63%,不是 100%。

因为 0.99¹⁰⁰ ≈ 0.366 —— 一次都不出的概率是 36.6%。

这里藏着两个最常见的错觉:

  1. “期望 100 次出” ≠ “100 次必出”。期望值是平均,不是保证。
  2. 抽了很多次没出,不代表"下次概率变大"。每一次都是独立的 1%。

五、大数定律:为什么"手气"是错觉

大数定律

试验次数越多,观测频率越接近真实概率。

实测抛硬币(20 组取平均和最大偏离):

n最偏离
100.40
1000.08
1,0000.019
10,0000.013
100,0000.0046
1,000,0000.0007

n 越大,偏离越小。 这是数学保证的,不是运气。

但注意:这不是"补偿"

很多人误解成"抛了 5 次正面,反面该来了"。这是赌徒谬误。

实测:连出 5 次正面后,第 6 次正面的概率:

实测 50.44%(理论 50.00%)

硬币没有记忆。 “该出反面了"是错觉。

大数定律说的不是"偏差会补回来”,是"偏差会被稀释"。 抛了 5 次正面,你已经偏离了 5 次。但接下来抛 10 万次,这 5 次的偏离在 10 万次里被稀释到可以忽略。 过去的偏离不会被"纠正",只会被"淹没"。


六、期望值:理性决策的唯一依据

概率论给你一个判断标准:期望值。

期望 = 每个结果的价值 × 它的概率,然后加起来。

彩票为什么是坑?因为期望值恒为负——你花的钱,大于你平均赢回来的钱。

抽卡为什么让人上瘾?因为稀有度×概率的期望值,被设计成"看起来值"但实际亏——而人脑对"小概率大回报"有系统性的高估。

在计算机里,期望值是无处不在的决策工具:

  • 缓存策略:存这个还是存那个?看哪个的"命中概率 × 命中收益"高
  • A/B 测试:哪个版本好?看哪个的期望指标高
  • 负载均衡:请求发给谁?期望让响应时间最短
  • 机器学习:损失函数本质就是"期望损失",训练就是在最小化它

用期望值做决策,是把"我觉得"换成"平均来看"。 单次可能错,长期必然对。


七、把这一篇放回体系

六篇讲完,八层目录已经走完前六层:

层状态
一 数怎么装进机器✅
二 离散结构✅
三 怎么保证对✅
四 什么能算✅
五 算得多快✅
六 不确定的世界✅ 本篇
七 连续的近似(微积分)待写
八 高维的表示(线代)待写

这一篇和前五篇的关系

前面五篇都在讲"确定":

  • 格点是确定的(一)
  • 离散结构是确定的(二)
  • 证明是确定的(三)
  • 可计算性是确定的(四)
  • 复杂度是确定的(五)

这一篇第一次引入"不确定"。 但它不是"放弃精确",而是给不确定装上数学框架:

  • 贝叶斯:不确定下怎么更新信念
  • 随机化:用不确定当工具,反而更快更准
  • 大数定律:不确定下的长期规律
  • 期望值:不确定下的决策标准

这是从"计算机是精确的"到"计算机活在不确定世界里"的转折。


八、动手:六个实验

实验 1:那个 99% 的检测

import random
random.seed(1)

def 模拟(患病率, 敏感性, 特异性, N=100000):
    病人 = int(N*患病率); 健康 = N - 病人
    TP = int(病人*敏感性); FP = int(健康*(1-特异性))
    pos = TP + FP
    return TP/(pos) if pos else 0

print(f"患病率 0.1%,99%/99%:阳性后真有病 {模拟(0.001,0.99,0.99)*100:.2f}%")
for prev in [0.001, 0.005, 0.01, 0.05, 0.1, 0.3]:
    print(f"  患病率 {prev*100:4.1f}% → {模拟(prev,0.99,0.99)*100:6.2f}%")

亲手看到"同样 99%,罕见病 9%、常见病 97%"。

实验 2:三门问题

import random
random.seed(4)
N = 200000; 换赢 = 不换赢 = 0
for _ in range(N):
    车 = random.randrange(3); 选 = random.randrange(3)
    可开 = [i for i in range(3) if i != 选 and i != 车]
    主持开 = random.choice(可开)
    换 = [i for i in range(3) if i != 选 and i != 主持开][0]
    if 换 == 车: 换赢 += 1
    if 选 == 车: 不换赢 += 1
print(f"不换 {不换赢/N*100:.1f}%  换 {换赢/N*100:.1f}%")

实验 3:生日悖论

import random
random.seed(4)
def 撞(m, trials=20000):
    hit = 0
    for _ in range(trials):
        b = [random.randrange(365) for _ in range(m)]
        if len(set(b)) < m: hit += 1
    return hit/trials
for m in [10, 20, 23, 30, 50]:
    print(f"{m:2d} 人 → {撞(m)*100:.1f}%")

实验 4:随机快排 vs 确定性快排(有序输入)

import random, sys, time
sys.setrecursionlimit(100000)
def q_det(a):
    if len(a) <= 1: return a
    return q_det([x for x in a[1:] if x < a[0]]) + [a[0]] + q_det([x for x in a[1:] if x >= a[0]])
def q_rand(a):
    if len(a) <= 1: return a
    i = random.randrange(len(a)); a = a[:]; a[0], a[i] = a[i], a[0]
    return q_rand([x for x in a[1:] if x < a[0]]) + [a[0]] + q_rand([x for x in a[1:] if x >= a[0]])

s = list(range(1000))
t = time.time(); q_det(s); print(f"确定性 {time.time()-t:.3f}s")
t = time.time(); q_rand(s); print(f"随机化 {time.time()-t:.3f}s")

实验 5:蒙特卡洛求 π

import random, math
random.seed(9)
def pi(n):
    inside = sum(1 for _ in range(n)
                 if (lambda x, y: x*x+y*y <= 1)(random.random(), random.random()))
    return 4*inside/n
for n in [1000, 100000, 10000000]:
    print(f"{n:>9,} 点 → {pi(n):.6f}  (π={math.pi})")

实验 6:赌徒谬误

import random
random.seed(42)
cnt = tot = 0
for _ in range(500000):
    seq = [random.random() < 0.5 for _ in range(6)]
    if all(seq[:5]):
        tot += 1
        if seq[5]: cnt += 1
print(f"连出 5 次正面后,第 6 次正面概率 {cnt/tot*100:.2f}%")

九、带走的东西

一句话:

世界是不确定的,概率是唯一能驾驭它的数学——而它反直觉到极致:用随机,反而能算得更快更准。

三句话:

  1. 贝叶斯定理:结论取决于"先验",不只取决于"证据"。 99% 准确的检测,罕见病上阳性后只有 9% 真有病——因为健康人太多,假阳性淹没了真阳性。
  2. 随机化算法:故意引入随机,消除最坏情况。 随机快排让"最坏输入"不存在;Miller-Rabin 用十亿分之一的可错概率,换"试除法永远算不完"变成"半毫秒"。
  3. 大数定律不是"补偿",是"稀释"。 硬币没有记忆,过去的偏离不会被纠正,只会被淹没。

一个最该记住的认知升级

前面五篇讲"确定",这一篇讲"不确定"。 但概率不是"放弃精确",是给不确定装上数学框架: 贝叶斯更新信念、随机化当工具、大数定律看长期、期望值做决策。

AI 的每一步——训练、推理、采样、决策——本质都是概率。 不懂这一篇,就看不懂 AI 在干什么。

下一篇

(七)连续的近似:微积分。为什么"梯度下降"能让 AI 学会东西、为什么"导数"是"变化率"、为什么计算机处理连续的世界要靠"逼近"而不是"精确"。

这一篇会把前面所有"离散"的东西,接到"连续"上——因为 AI 的底层,就是在用离散的机器逼近连续的数学。

深水区

  • 概率论主干:任意一本《概率论》教材,或 Sheldon Ross《A First Course in Probability》。
  • 贝叶斯:E.T. Jaynes《Probability Theory: The Logic of Science》——把贝叶斯讲到哲学高度的名著。
  • 随机化算法:Mitzenmacher & Upfal《Probability and Computing》——概率和算法的结合,正好接这一篇。
  • 蒙特卡洛:任何一本《Monte Carlo Methods》教材。

这些我不做页码引用——不同版本页码不同,写了就是骗你。按书名和章节找。


附:本篇所有数字的来源

全部本机跑出来:Ubuntu / Python 3.8 / x86-64。

贝叶斯:患病率 0.1%、敏感性 99%、特异性 99%,10 万人模拟 → 真阳 99、假阳 999、PPV=9.02%;不同患病率 0.1%/0.5%/1%/5%/10%/30% → 9.02%/33.22%/50.00%/83.90%/91.67%/97.70%。

随机快排(有序输入):n=300/600/1000,确定性 5.5/19.5/41.8 ms,随机化 0.7/1.7/1.7 ms。

Miller-Rabin vs 试除:1,000,003 → 0.15 vs 0.04 ms;1,000,000,007 → 4.61 vs 0.05 ms;1,000,000,000,039 → 189.33 vs 0.12 ms;2¹²⁷−1 → 试除不可行 vs 0.7 ms。

蒙特卡洛 π:1k/10k/100k/1M/10M 点 → 3.140000/3.152800/3.145200/3.138636/3.141839(误差 1/√n 收敛)。

三门问题:20 万次,不换 33.26%、换 66.74%(理论 33.33%/66.67%)。

生日悖论:10/20/23/30/50 人 → 11.8%/41.0%/51.4%/70.5%/97.0%。

抽卡 1% 出率:10/50/100/200/300 次 → 9.5%/39.4%/63.5%/86.7%/95.0%。

大数定律:抛硬币 n=10~100 万,最大偏离 0.40→0.0007。

赌徒谬误:连出 5 次正面后第 6 次 50.44%(理论 50%)。

你自己机器上跑出来的数字会略有不同。差一点不影响结论——结论是结构性的。