概率分布就是把「不确定」写成函数:横轴是可能的结果,纵轴是它有多大概率。 一旦写成这个形状,剩下的问题就只剩一个:参数该取多少? 答案通常是极大似然:挑一个让「已经发生的事」最不意外的参数。抛一百次硬币出了六十三次正面, 那个参数就是 0.63。
第 5 章处理的全是「确定的数」:给一组点,求一条线;给一张图,找一条路。 这一章开始处理「不确定」:数据本身带着抖,答案也只能给一个范围。 这一节是整章的底座。6.2 的贝叶斯要在这个分布上加一个先验,6.3 的 MCMC 要在这个分布上抽样, 6.4 的 HMM 用这些分布当零件。先把「一个分布长什么样」这件事讲透,后面三节才有东西可加。
一、分布是什么:一张「结果对应概率」的表
抛十次硬币,正面次数可能是 0 到 10 里的任何一个。 「每个结果有多大概率」把这件事写出来,就是一个分布。 离散的和连续的要分开说。离散的结果可以一个个数出来(几次、几个、哪一类), 概率直接落在每个结果上; 连续的结果数不完(长度、时间、重量), 问「恰好等于 3.0000」的概率是 0,只能问「落在某个区间里」。
| 叫法 | 用在 | 回答什么 |
|---|---|---|
| 概率质量(PMF) | 离散 | 正好等于 k 的概率 |
| 概率密度(PDF) | 连续 | 落在某段区间里的概率(要对密度积分) |
| 这个区别不是学术洁癖。下面会看到:把「密度」当成「概率」直接读, | ||
| 会得出「密度大于 1 就是错」这种误会——密度可以大于 1,只要它积起来是 1。 |
二、三个最常用的分布,各自回答什么问题
分布有成百上千个,但日常九成的场合只用三个。分不清该用哪个,往往是因为没问清「我在数什么」。
| 分布 | 在数什么 | 两个参数 | 典型例子 |
|---|---|---|---|
| 二项 | 固定次里成功几次 | 次数 n、成功概率 p | 十次射击中几次 |
| 泊松 | 一段时间里来几个 | 平均发生率 λ | 一小时来几通电话 |
| 正态 | 一个连续量的取值 | 中心 μ、宽度 σ | 测量误差、身高 |
| 头两行最容易混。二项有上限(最多 n 次),泊松没有上限——一小时来几通电话, | |||
| 理论上可以是 100 通。Demo 里二项在 k=10 之后就没有了,泊松到 k=10 还有 0.0002 的概率。 | |||
| 正态那一行要单独说一句。它的三个口诀「68.3%、95.4%、99.7%」(一个、两个、 | |||
| 三个标准差)在 Demo 里是数值积分算出来的,不是查表抄的。 | |||
| 这两个数之所以能背,是因为它们跟具体问题无关——只要真是正态,换成米、换成秒都一样。 |
三、从数据里把参数挖出来:极大似然
分布的形状定了,就只剩参数。抛 100 次硬币出了 63 次正面,那个「正面概率 p」该取多少? 极大似然的想法很朴素: 挑一个 p,让「出现这组结果」的概率最大。出现这组结果的概率是 p 的 63 次方乘 (1−p) 的 37 次方, 扫一遍就知道峰在哪儿。
| p | 对数似然 | 说明 |
|---|---|---|
| 0.10 | −148.96 | 太低,出不了这么多正面 |
| 0.46 | −71.72 | 上坡中 |
| 0.63 | −65.92 | 峰顶 |
| 0.73 | −68.27 | 已经翻过去了 |
| 0.91 | −95.04 | 太低,几乎不该出反面 |
| 峰正好在 0.63,也就是「正面次数除以总次数」。求导也能得到同一个答案:对数似然对 p 求导、 | ||
| 令其为零,解出来就是 63/100。 | ||
| 这不是巧合,是极大似然最常见的一个结论—— | ||
| 对这类「成/不成」的问题,最合理的估计就是样本里的比例。 | ||
| 为什么要取对数?因为概率是连乘的,连乘几十项就会下溢成 0; | ||
| 取了对数变成连加,数值上稳得多,而且峰的位置一模一样(对数是单调的)。 | ||
| 所以实际代码里几乎从不直接算似然,都算对数似然。 |
四、为什么方差要除以 n−1
这件事在教科书里常被当成一个公式记住, 其实它是一次可以量出来的偏差。从一个方差为 4 的分布里抽 1000 个数,两种算法各算一遍, 重复 2000 次:
| 算法 | 两千次平均 | 相对真值 |
|---|---|---|
| 除以 n | 3.9945 | 偏小 |
| 除以 n−1 | 3.9985 | 基本不偏 |
| 真值 | 4.0000 | — |
| 别盯着单列看,看两列之差:0.0040,正好等于「真值除以 n」。这个数不是估出来的, | ||
| 是算出来的——配对相减之后,抽样的随机误差互相抵消了,剩下的就是这一份系统偏差。 | ||
| 为什么会有这个偏差?因为算方差之前,先用这批数据算出了均值。 | ||
| 而均值总会往数据中心靠,于是每个数到中心的距离都被压短了一点点。除以 n−1 就是在补这一下。 | ||
| 样本越小,补得越多:n=10 时差 10%, | ||
| n=1000 时只差 0.1%——这也是为什么大样本时这两个公式几乎没区别。 |
五、为什么正态分布到处都是
从一个根本不像正态的分布里抽样——指数分布(等车时间),大量小值、右边一条长尾巴。 每次抽 n 个求平均,重复 5000 次,看这个平均值有多宽:
| 每次抽几个 | 实测波动 | 理论 1/√n | 比值 |
|---|---|---|---|
| 1 | 1.0041 | 1.0000 | 1.004 |
| 5 | 0.4528 | 0.4472 | 1.013 |
| 30 | 0.1801 | 0.1826 | 0.987 |
| 100 | 0.0989 | 0.1000 | 0.989 |
| 400 | 0.0503 | 0.0500 | 1.007 |
| 五行的比值都在 1 附近,说明「波动按 1/√n 缩小」是硬规律,跟原始分布无关。 | |||
| 更关键的是形状:抽 30 个求平均之后,这个平均值的分布已经很像正态了,哪怕原始数据是指数分布。 | |||
| 这就是中心极限定理。 | |||
| 它顺手解释了「误差为什么几乎总是正态的」。一个测量误差往往是很多小因素叠加的结果(手抖、温度、 | |||
| 读数、换算),叠加就是求和,求和就是平均,于是不管每个小因素长什么样,合起来都趋近正态。 | |||
| 1/√n 这个比例还有一个很实际的推论:想让精度翻倍,样本要翻四倍。 | |||
| 这是所有「多测几次取平均」的办法背后真正的那笔账——它比大多数人的直觉贵得多。 |
六、选分布就是选形状
最后一个问题:手里这批数据,到底该套哪个分布?答案不是「选更高级的」,而是「选形状对得上的」。 Demo 拿两组参数一样多的模型去套同一批右偏数据:
| 模型 | 参数个数 | 对数似然 |
|---|---|---|
| 正态 | 2 | −1523.10 |
| 对数正态 | 2 | −1293.82 |
| 参数一样多,对数似然差 229.28。差 1 就是 e 倍, | ||
| 差 229 就是 e 的 229 次方倍——这个倍数大到没意义,只说明一件事:方向对了,差得很远。 | ||
| 对数正态赢在形状:它的对数才是正态,所以天生右偏、拖长尾,跟指数型的数据是一路的。 | ||
| 正态则是对称的,用对称的去套右偏的,两头都要吃亏:左边被拉出去,右边压不住。 | ||
| 顺便记一个陷阱:参数多的模型似然一定更高,这跟它准不准没关系。所以比较模型时要么固定参数个数, | ||
| 要么用 AIC 这类带罚项的指标。Demo 里特意让两边都只有两个参数,就是为了绕开这个坑。 |
七、动手 Demo:三种分布,和「从数据里把参数挖出来」
前三段是「看形状」,后三段是「估参数」。三种分布的密度函数都手写了, 没有调任何库——二项要用组合数,泊松要用阶乘,正态的那个 √(2π) 也得自己写。 最值得自己重跑一遍的是第四段那个方差。它把「除以 n 偏小」从一个公式变成了一列能看的数, 而且差多少也能算准。
def binom_pmf(k, n, p): # 二项:n 次里正好 k 次
return comb(n, k) * p ** k * (1 - p) ** (n - k)
def pois_pmf(k, lam): # 泊松:一段时间里正好 k 个
return np.exp(-lam) * lam ** k / factorial(k)
def norm_pdf(x, mu, sd): # 正态:连续,问区间概率
return np.exp(-0.5 * ((x - mu) / sd) ** 2) / (sd * np.sqrt(2 * np.pi))
# 极大似然:扫一遍 p,挑让「已经发生的事」最不意外的那个
g = np.linspace(0.01, 0.99, 99)
ll = 63 * np.log(g) + 37 * np.log(1 - g) # 100 次里 63 次正面
p_hat = g[ll.argmax()] # 0.63
# 方差的两个分母:配对相减,抽样误差会抵消,只剩系统偏差
for _ in range(2000):
x = rg.normal(5.0, 2.0, 1000)
v = ((x - x.mean()) ** 2).mean()
e_n.append(v) # 除以 n,系统性偏小
e_n1.append(v * 1000 / 999) # 除以 n−1
# 中心极限定理:不管原始分布什么样,平均值都按 1/√n 收窄
for n in (1, 5, 30, 100, 400):
s = rg.exponential(1.0, (5000, n)).mean(1)
print(n, s.std(), 1 / np.sqrt(n))
实跑输出:
--------------------------------------------------------------------
三种分布,和「从数据里把参数挖出来」
--------------------------------------------------------------------
==============================================================
[1] 分布是用来回答「多大概率」的
二项分布 B(10, 0.3):抛十次硬币(正面概率 0.3),正好 k 次正面的概率。
k= 0 0.0282 ####
k= 1 0.1211 ##################
k= 2 0.2335 ###################################
k= 3 0.2668 ########################################
k= 4 0.2001 ##############################
k= 5 0.1029 ###############
k= 6 0.0368 ######
k= 7 0.0090 #
k= 8 0.0014
k= 9 0.0001
k=10 0.0000
泊松分布 P(2.5):一段时间里平均来 2.5 个事件,正好来 k 个的概率。
k= 0 0.0821 #############
k= 1 0.2052 ################################
k= 2 0.2565 ########################################
k= 3 0.2138 #################################
k= 4 0.1336 #####################
k= 5 0.0668 ##########
k= 6 0.0278 ####
k= 7 0.0099 ##
k= 8 0.0031
k= 9 0.0009
k=10 0.0002
两种形状都是「中间高、两头低」,但**二项有上限(最多十次),泊松没有**。
这个差别不是细节:**二项数的是「几次里成功几次」,泊松数的是「一段时间里来几个」。**
正态分布 N(0, 1) 是连续的那一类,问的是「落在某个区间里的概率」。
三个区间实测一遍(数值积分,不查表):
区间 实算概率 常说的数
--------------------------------------------------
±1 个标准差 0.6827 68.3%
±2 个标准差 0.9545 95.4%
±3 个标准差 0.9973 99.7%
**这三个数之所以能背,是因为它们跟具体问题无关**——只要真是正态,换什么单位都成立。
[2] 一百次抛硬币,正面概率到底是多少
真实情况:抛 100 次,63 次正面。**问题是:那个「正面概率 p」该取多少?**
极大似然的做法是:**找一个 p,使得「出现这组结果」的概率最大。**
出现这组结果的概率是 p 的 63 次方乘 (1−p) 的 37 次方。扫一遍看:
p 对数似然 形状
----------------------------------------------------
0.01 -290.498
0.10 -148.961 ··················
0.19 -112.423 ······················
0.28 -92.351 ·························
0.37 -79.733 ··························
0.46 -71.720 ···························
0.55 -67.209 ····························
0.64 -65.917 ····························
0.73 -68.272 ····························
0.82 -75.950 ···························
0.91 -95.036 ························
最高点在 p = 0.63。**为什么正好是 0.63?**它本来就是「正面次数除以总次数」。
求导也能得到同一个答案:对数似然对 p 求导、令其为零,解出 p = 63/100。
**这就是极大似然估计:挑一个让「已经发生的事」最不意外的参数。**
[3] 方差的那个分母:n 还是 n−1
真值:从 N(5, 2) 里抽样,总体方差是 4。抽 1000 个,两种算法各算一遍,
重复 2000 次,看它们平均下来偏不偏:
算法 两千次平均 真值 偏差
----------------------------------------------------------
除以 n 3.9945 4.0000 -0.0055
除以 n−1 3.9985 4.0000 -0.0015
**两列之差 0.0040,正好等于「真值除以 n」,也就是 4/1000 = 0.004。**
配对相减之后,抽样的随机误差被抵消掉了,剩下的就是这一份系统偏差。
原因很朴素:**算方差之前先用这批数据算出了均值,**
**而均值会往数据中心靠,于是每个数到中心的距离都被压短了一点点。**
除以 n−1 就是在补这一下。**样本越小,补得越多**——n=10 时差 10%,n=1000 时差 0.1%。
[4] 拿泊松去套一批真的计数数据
模拟 800 天,每天来的事件数服从泊松(每天平均 2.5 个)。
然后只拿这批数去估参数、算理论频数,看套不套得上:
从数据估出来的 λ = 2.5000(真值 2.5)
来了几个 实际天数 理论天数 差
----------------------------------------------
0 66 65.7 +0.3
1 169 164.2 +4.8
2 190 205.2 -15.2
3 171 171.0 -0.0
4 120 106.9 +13.1
5 57 53.4 +3.6
6 19 22.3 -3.3
7 6 8.0 -2.0
8 1 2.5 -1.5
每一档都对得上,差值最大也就十几——**这就是「这个模型能描述这批数据」的样子。**
**注意这里做的是两件事:先估参数,再看形状。**估参数只看一个数(均值),看形状要看一整列。
[5] 为什么正态分布到处都是
从一个根本不像正态的分布里抽样:指数分布(等车时间),大量小值、长尾巴。
每次抽 n 个求平均,重复 5000 次,看**平均值**的分布有多宽:
每次抽几个 n 平均值实际波动 理论 1/√n 比值
----------------------------------------------------------
1 1.0041 1.0000 1.004
5 0.4528 0.4472 1.013
30 0.1801 0.1826 0.987
100 0.0989 0.1000 0.989
400 0.0503 0.0500 1.007
单抽一个(n=1)实测波动 1.0041,抽 400 个求平均只剩 0.0503——**基本按 1/√n 缩小。**
更关键的是形状:**抽 30 个求平均之后,这个平均值的分布已经很正态了,**
**哪怕原始数据是指数分布。**
这就是中心极限定理。**它解释了为什么「误差」几乎总是正态的**:
一个测量误差往往是很多小因素叠加的结果,**叠加就是求和,求和就是平均。**
[6] 模型好不好,用什么尺子量
两个模型套同一批数据,比较它们的对数似然。
但有个陷阱:**参数多的模型似然一定更高,这跟它准不准没关系。**
这批数据是指数分布右移一位:大量小值挤在左边,右边拖一条长尾。
用正态拟合:μ = 3.938,σ = 3.064,对数似然 -1523.10,参数 2 个
用对数正态拟合:对数似然 -1293.82,参数还是 2 个
**参数一样多,对数似然差 229.28。**差 1 就是 e 倍,差 229 就是 e 的 229 次方倍——
这个倍数大到没意义,只说明一件事:方向对了,差得很远。
对数正态赢了,因为**它的形状本来就是对的方向**:右偏、长尾。
**这就是选分布的全部道理:不是选「更高级的」,是选「形状对得上的」。**
第一段的柱状图有个细节要看:二项到 k=10 就是最后一格,泊松到 k=10 还没完。 这就是「有上限」和「没上限」的差别。 实际建模时选错了这一点,后果很直接:用泊松去拟合「十次射击中几次」这种有天花板的数据, 会算出「命中 11 次」的概率大于 0。 第三段那张对数似然的曲线,最该记的是它的宽度。峰在 0.63, 但 0.55 和 0.73 只差几个单位—— 这说明「63 次正面」对 p 的约束并不紧。换成 630 次正面(同样的比例),这条曲线会窄得多。 样本量决定的是这条曲线的陡峭程度,不是峰的位置。 第四段那两列如果分开看,都会觉得「差不多」。3.9945 和 3.9985,差 0.004,看着像噪声。 但配对相减之后 0.0040 稳稳地待在同一个数上——这正是「系统偏差」和「随机误差」的区别: 随机的会抵消,系统的不会。这个判据在别处也用得上: 重复实验一百次,偏差还在,那就不是运气问题。 第六段的结论比数字重要。两台模型参数一样多、数据一样,对数似然差 229, 这不是「一个稍微好一点」,是「一个根本不对」。所以真实工作里的顺序永远是: 先看形状(画图),再估参数,最后才比指标。反过来做, 很容易在一堆都不合适的模型里挑出一个「最好的」。
30 秒实验
- 把第三段的 63 改成 630、总次数改成 1000,重跑。 峰还在 0.63,但曲线陡得多——同样比例、十倍样本,对 p 的约束紧了一大截。 这就是「样本量买的是精度」。
- 把第五段的
exponential换成rg.random(n)(均匀分布,0 到 1),重跑。 1/√n 那一列还是对得上——中心极限定理不挑原始分布,这是它的全部威力所在。 - 把第六段的右偏数据换成一批正态数据(
rg.normal(0, 1, 600)),重跑。 这回正态赢,对数正态会因为「不能取负数」而吃亏。 这说明选分布没有通用答案,只有「跟数据配不配」。
常见误区
- 以为「概率密度」就是「概率」。密度可以大于 1(比如 N(0, 0.1) 在 0 处的密度约 4.0), 因为它不是概率,是「单位长度上的概率」。要得到概率必须积分。 把密度直接当概率读,就会得出「密度 4.0,概率 400%」这种荒谬结论。
- 以为正态分布是「默认选项」。它只是因为中心极限定理在「求和」的场合特别好使。 涉及「等待时间」「金额」「人口」这类右偏的量,正态往往很糟—— Demo 第六段那个 229 的差距就是代价。
- 以为除以 n 才是「定义」,n−1 是个修正。两个都有人用: 除以 n 是「这批数据的方差」,除以 n−1 是「对总体方差的无偏估计」。问法不同,答案不同。 写代码时想清楚「我要描述这批数,还是要估计那个总体」。
- 以为极大似然一定最好。它只保证「让已观测的数据最不意外」, 不保证接近真值。样本小的时候它很容易给出极端答案(全是正面就给 1.0), 这正是下一节贝叶斯要修的地方。
自测三问(点开对答案)
1. 为什么二项分布和泊松分布长得像,却不能混用? —— 因为**二项有上限,泊松没有**。二项数的是「固定 n 次里成功几次」,成功次数不可能超过 n; **泊松数的是「一段时间里来几个」,理论上没有天花板。**当 n 很大、p 很小时, 两者数值上会非常接近(泊松本来就是二项的极限), **但「有没有上限」这件事在建模时是硬约束,不能含糊。** 2. 为什么方差公式要除以 n−1 而不是 n? —— 因为**算方差之前先用同一批数据算了均值**。 均值会往数据中心靠,**于是每个数到中心的距离都被系统性压短了一点**,除出来的方差就偏小。 Demo 里量出来这个偏差正好是「真值除以 n」(4/1000 = 0.004)。 **除以 n−1 就是把这一点补回来**——样本越小,补得越多。 3. 中心极限定理说的到底是哪件事? —— 说的是:**不管原始分布长什么样,只要各个样本独立、方差有限,样本均值就会趋近正态,** **波动按 1/√n 缩小。**注意它讲的是「均值」的分布, **不是原始数据的分布**——原始数据可以是指数分布、均匀分布、甚至双峰,均值照样趋近正态。 **这是「正态到处都是」的唯一原因,也是「多测几次取平均」的理论依据。**这一节一直默认「参数是固定的,只是我们不知道」。 下一节换一个立场:参数本身也有分布。这个小小的转向,带出了先验、后验、收缩, 还有一个能真干活的分类器。
- ☐ (本节完,下一节 6.2 贝叶斯统计学和贝叶斯估计)