暗无天日

=============>DarkSun的个人博客

中心极限定理:为什么随机世界总会产生钟形曲线

钟形曲线无处不在

量一千个人的身高,画成分布图,你会看到一条中间高、两边低的对称曲线,形状像一口倒扣的钟。这就是正态分布,日常叫它钟形曲线。

换成考试成绩、降雨量、新生儿体重,结果都一样:只要你收集的数据足够多,形状总是一口钟。

这是为什么?世间万事万物如此不同,凭什么都服从同一个形状?

答案是一个叫 *中心极限定理*(Central Limit Theorem,简称 CLT)的数学结论。它说的是:不管原始数据是什么分布,只要把足够多次独立观测的结果拿来取平均,平均值就会服从正态分布。这个结论看起来很不可思议,但它是整个现代统计学的基础。

赌徒的发现

这个发现要从赌博说起。

18 世纪初的伦敦,数学家 Abraham de Moivre 靠给赌徒当顾问谋生。他的才华得到过牛顿和哈雷的认可,但作为法国新教难民,他在英国拿不到正式的教职,只能用数学本事换饭吃。

de Moivre 研究了抛硬币的问题。抛 100 次硬币,正面朝上的次数大概是 50 次左右,但不会精确地等于 50。重复玩很多遍,每次的结果都不一样。然而,当你把所有结果画成频率图时,一个清晰的形状浮现出来:中间最高(50 次附近),两边对称下降。这就是正态分布。

de Moivre 算出了这条钟形曲线的精确形状,写进了 1738 年出版的《机会论》(The Doctrine of Chances)一书。但他没有意识到自己的发现有多大的通用性。几十年后,法国数学家 Laplace 在 1810 年把它推广为一个通用定理:不管随机过程本身是什么规律,只要取足够多次的均值,结果就服从正态分布。这就是后来的中心极限定理。

CLT 到底说了什么

中心极限定理可以用一句话概括:

取很多个互相独立的随机数的平均值,这个平均值服从正态分布。

关键条件是互相独立。每次抛硬币的结果不会影响下一次,每次掷骰子也不会受到上一次的影响。只有当观测之间互不干扰时,CLT 才成立。

这个定理最厉害的地方在于,它不关心原始数据是什么分布。抛硬币、掷骰子、测身高,原始规律完全不同,但取均值后都会变成同一种形状。

我们用代码来看看这个过程。

抛 100 枚硬币,数正面朝上有几枚。重复 10000 次,把结果画成频率分布:

import random
from collections import Counter

random.seed(42)

# 抛 100 枚硬币,数正面朝上的数量,重复 10000 次
results = []
for _ in range(10000):
    heads = sum(1 for _ in range(100) if random.random() < 0.5)
    results.append(heads)

# 按 5 个一组统计频次
buckets = Counter()
for h in results:
    buckets[h // 5 * 5] += 1

# 画 ASCII 直方图
max_freq = max(buckets.values())
for bucket in range(30, 70, 5):
    freq = buckets.get(bucket, 0)
    bar_len = int(freq / max_freq * 50)
    print(f"{bucket:3d}-{bucket+4:3d}: {'█' * bar_len} ({freq})")
30- 34:  (12)
35- 39: ██ (175)
40- 44: ████████████████ (1180)
45- 49: ██████████████████████████████████████████████ (3273)
50- 54: ██████████████████████████████████████████████████ (3523)
55- 59: █████████████████████ (1545)
60- 64: ███ (270)
65- 69:  (22)

每次抛 100 枚硬币,正面朝上的次数总是聚集在 50 附近。离 50 越远,出现的频率越低。这就是钟形曲线。

均匀分布也能变钟形

你可能会想,硬币只有正反两面,正面 50%、反面 50%,这个分布太简单了,产生钟形曲线不奇怪。

那我们换一个完全不同的分布:掷骰子。

骰子有 6 个面,每个面朝上的概率相等(都是 1/6)。如果你掷 10000 次骰子,记录每个面的出现次数,频率图是完全平坦的,没有钟形。

import random
from collections import Counter

random.seed(42)

# 单骰子:掷 10000 次
single = Counter(random.randint(1, 6) for _ in range(10000))
for face in range(1, 7):
    bar = '█' * (single[face] // 30)
    print(f"  {face}: {bar} ({single[face]})")
1: █████████████████████████████████████████████████████ (1618)
2: ██████████████████████████████████████████████████████ (1629)
3: ██████████████████████████████████████████████████████ (1647)
4: ████████████████████████████████████████████████████████ (1687)
5: ███████████████████████████████████████████████████████ (1671)
6: ██████████████████████████████████████████████████████████ (1748)

六个面出现的频率几乎一样高,看不出任何钟形的影子。

现在改变做法:每次掷 10 个骰子,取它们的平均值。重复 10000 次,看平均值的分布:

import random
from collections import Counter

random.seed(42)

# 十骰子取平均:重复 10000 次
avg_counts = Counter()
for _ in range(10000):
    total = sum(random.randint(1, 6) for _ in range(10))
    avg = round(total / 10, 1)
    bucket = round(avg * 2) / 2  # 四舍五入到最近的 0.5(如 3.3→3.5, 3.8→4.0)
    avg_counts[bucket] += 1

max_freq = max(avg_counts.values())
for bucket in sorted(avg_counts):
    freq = avg_counts[bucket]
    bar_len = int(freq / max_freq * 40)
    print(f"  {bucket:.1f}: {'█' * bar_len} ({freq})")
1.5:  (1)
2.0:  (81)
2.5: ████████ (728)
3.0: ██████████████████████████ (2392)
3.5: ████████████████████████████████████████ (3556)
4.0: ██████████████████████████ (2382)
4.5: ████████ (766)
5.0: █ (90)
5.5:  (4)

钟形出来了。原始分布是完全平坦的,但只要取 10 个数的均值,重复足够多次,均值就变成了钟形分布。

这就是中心极限定理的魔力。不管你从什么分布里抽样,只要样本够多、取均值,结果就趋近正态分布。骰子的原始分布没有任何钟形的痕迹,但取均值后钟形自动出现了。

为什么它自动出现

理解了 CLT 的机制,就能解释为什么自然界中到处都是钟形曲线了。

以身高为例。一个人的身高受很多因素影响:父亲的身高、母亲的身高、基因组合、孕期营养、童年营养、运动量、睡眠质量,等等。这些因素互相之间基本独立(你爸的身高不会影响你小时候吃什么),每个因素的贡献都很小。

当很多个微小的、互相独立的因素叠加在一起时,效果就相当于取均值。根据中心极限定理,这个均值服从正态分布。所以人的身高自动呈现钟形曲线,不需要任何外力来塑造它。

考试成绩也是类似的道理。一套设计合理的试卷,分数由大量互不相关的因素决定:这道题你会不会、那道题有没有粗心、这道题时间够不够。因素足够多、足够独立,总分就服从正态分布。

这就是为什么钟形曲线不需要被设计,它会自己长出来。只要一个量背后隐藏着很多个独立因素叠加的过程,这个量就几乎必然呈现正态分布。

判断真伪的力量

CLT 不只是解释了自然界为什么有这么多钟形曲线,它还给了科学家一个强大的工具:判断异常。

回到 de Moivre 时代的咖啡馆。有人递给你一枚硬币,跟你打赌。你抛 100 次,正面朝上不到 45 次就算他赢。你抛了,结果只有 20 次正面。这枚硬币公平吗?

多亏了中心极限定理,你知道正面次数服从正态分布,均值 50。100 次抛硬币(二项分布)的标准差可以用公式 √(n×p×(1−p)) 算出来,n=100、p=0.5,所以标准差 = √25 = 5。20 次正面距离均值有 (50−20)/5 = 6 个标准差之远。在正态分布中,偏离均值 6 个标准差以上的概率几乎为零(大约十亿分之一)。

你可以非常自信地说:这枚硬币被动过手脚。

正态分布有一个实用的性质,叫 68/95 法则:

  • 大约 68% 的数据落在均值上下 1 个标准差范围内
  • 大约 95% 的数据落在均值上下 2 个标准差范围内

我们用代码验证一下。抛 100 枚硬币(标准差是 5),看正面次数有多少落在 50±5 和 50±10 的区间内:

import random

random.seed(42)

# 抛 100 枚硬币,数正面,重复 10000 次
results = []
for _ in range(10000):
    heads = sum(1 for _ in range(100) if random.random() < 0.5)
    results.append(heads)

# 统计各区间占比
within_5 = sum(1 for h in results if 45 <= h <= 55)
within_10 = sum(1 for h in results if 40 <= h <= 60)
total = len(results)

print(f"正面 45-55 次(离均值偏差不超过 5): {within_5/total*100:.1f}%")
print(f"正面 40-60 次(离均值偏差不超过 10): {within_10/total*100:.1f}%")
print()
print("正态分布理论值:±1σ 约 68%,±2σ 约 95%")
print("(模拟值略高,因为整数区间比连续分布的±1σ稍宽)")
正面 45-55 次(离均值偏差不超过 5): 72.7%
正面 40-60 次(离均值偏差不超过 10): 96.3%

正态分布理论值:±1σ 约 68%,±2σ 约 95%
(模拟值略高,因为整数区间比连续分布的±1σ稍宽)

模拟值(72.7% 和 96.3%)比理论值(68% 和 95%)略高。原因是硬币正面次数是整数。代码中 45 ≤ h ≤ 55 包含了 45 和 55 两个端点,共 11 个整数。在连续分布中,整数 45 实际占据 44.5 到 45.5 的范围,55 占据 54.5 到 55.5。所以 11 个整数实际覆盖的连续范围是 44.5 到 55.5,宽度是 11,比 1 个标准差的宽度(10)多了一点。但趋势完全一致。绝大多数结果集中在均值附近,偏离越远越罕见。

这个原理是统计推断的基石。科学家做实验、分析师做 A/B 测试、质检员抽检产品,判断结果是否正常的逻辑都建立在 CLT 之上。你知道均值和标准差,就能算出某个结果出现的概率,概率太低就说明有问题。

CLT 的局限性

CLT 虽然强大,但不是万能的。它有三个前提:

  1. 样本要互相独立。 如果你在一个缅因州的小镇上做全国民调,不管重复多少次,结果都不会变成正态分布,因为样本本身有系统性偏差。
  2. 样本量要够大。 CLT 说的是足够多次取均值的极限行为。实际中,样本量太小时(通常少于 30),正态近似的效果会很差。
  3. 极端事件比平均值更重要。 "百年一遇"的洪水最近频繁发生,这时候关注平均水位没有意义,你需要研究的是分布的尾部。极端事件的建模用的是另一套工具(极值理论),不是 CLT。

尽管有这些限制,CLT 仍然是经验科学的支柱。几乎每次科学家用测量数据推断世界规律时,CLT 都隐藏在方法背后。没有它,科学很难对任何事情给出有信心的结论。

概率论 : 统计 : 正态分布