这是 数学重学路线图 阶段四的子页面
概率分布:每个可能结果的”剧本”
直觉入门:概率分布是什么?
想象你站在一个弹珠机前面
每颗弹珠落下,最终会落入某个槽里
概率分布就是描述”每个槽会接住多少比例弹珠”的完整地图
核心规则只有两条:
每个结果的概率 ≥ 0(不可能是负概率)
所有可能结果的概率加起来 = 1(弹珠总要落在某个地方)
类比:概率分布就像后端服务的流量分配表——每条路径分到多少流量,加起来就是 100%
离散分布:可数的结果
伯努利分布 Bernoulli
最简单的分布:一次试验,两种结果
成功概率 p,失败概率 1-p
比喻:一次 API 调用,要么成功(p),要么失败(1-p)
$P(X=1) = p, \quad P(X=0) = 1-p$
期望 $E(X) = p$,方差 $Var(X) = p(1-p)$
二项分布 Binomial B(n, p)
n 次独立伯努利试验中,成功 k 次的概率
公式:
$P(X=k) = C(n,k) \cdot p^k \cdot (1-p)^{n-k}$
其中 $C(n,k) = \frac{n!}{k!(n-k)!}$
直觉:n 次请求中恰好 k 次失败的概率是多少?
期望 $E(X) = np$,方差 $Var(X) = np(1-p)$
应用场景:
100 次请求中出现 5 次超时的概率
1000 个用户中有多少会点击某个按钮
安全扫描 n 个端口,恰好 k 个开放
Python 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| from scipy import stats import matplotlib.pyplot as plt import numpy as np
n, p = 100, 0.05 binom_dist = stats.binom(n, p)
x = np.arange(0, 20) pmf = binom_dist.pmf(x)
plt.figure(figsize=(10, 5)) plt.bar(x, pmf, color='steelblue', alpha=0.8) plt.xlabel('失败次数 k') plt.ylabel('P(X=k)') plt.title(f'二项分布 B({n}, {p}):100次请求中失败次数的概率') plt.axvline(x=n*p, color='red', linestyle='--', label=f'期望 E(X)={n*p}') plt.legend() plt.show()
prob_at_least_10 = 1 - binom_dist.cdf(9) print(f"至少10次失败的概率: {prob_at_least_10:.4f}")
|
泊松分布 Poisson(λ)
单位时间/空间内事件发生次数
公式:
$P(X=k) = \frac{\lambda^k \cdot e^{-\lambda}}{k!}$
λ 是单位时间内的平均发生次数
直觉:如果平均每分钟来 5 个请求,那某一分钟来 10 个请求的概率是多少?
期望 $E(X) = \lambda$,方差 $Var(X) = \lambda$(期望=方差是泊松分布的标志)
与二项分布的关系:当 n 很大、p 很小、np=λ 时,二项分布近似泊松分布
应用场景:
每分钟收到的请求数
每天发现的 Bug 数
每小时的安全告警数
DDoS 检测:请求数突然远超 λ
Python 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| from scipy import stats import matplotlib.pyplot as plt import numpy as np
lam = 5 poisson_dist = stats.poisson(lam)
x = np.arange(0, 20) pmf = poisson_dist.pmf(x)
plt.figure(figsize=(10, 5)) plt.bar(x, pmf, color='coral', alpha=0.8) plt.xlabel('事件次数 k') plt.ylabel('P(X=k)') plt.title(f'泊松分布 Poisson(λ={lam}):每分钟请求数分布') plt.axvline(x=lam, color='red', linestyle='--', label=f'λ={lam}') plt.legend() plt.show()
prob_over_12 = 1 - poisson_dist.cdf(12) print(f"请求超过12个/分钟的概率: {prob_over_12:.6f}") print(f"如果发生了,大概率是异常!")
|
几何分布 Geometric
首次成功需要的试验次数
$P(X=k) = (1-p)^{k-1} \cdot p$
直觉:暴力破解密码,平均试多少次能成功?
连续分布:不可数的结果
区间 [a, b] 内每个值出现的概率密度相同
概率密度函数:$f(x) = \frac{1}{b-a}$,在 [a,b] 内
直觉:random() 生成 [0,1] 之间的随机数,就是均匀分布
应用:
随机数生成(密码学基础)
负载均衡中的随机分配
AB 测试中的随机分组
正态分布 Normal(μ, σ²)
最重要的分布,自然界无处不在
钟形曲线:μ 决定中心位置,σ 决定宽窄
概率密度函数:
$f(x) = \frac{1}{\sigma\sqrt{2\pi}} e^{-\frac{(x-\mu)^2}{2\sigma^2}}$
68-95-99.7 法则:
68% 的数据落在 μ±1σ 内
95% 的数据落在 μ±2σ 内
99.7% 的数据落在 μ±3σ 内
直觉:API 响应时间的分布——大部分集中在均值附近,极快极慢的都少
中心极限定理 CLT:
无论原始分布是什么,大量独立样本的均值近似正态分布
这就是正态分布如此重要的根本原因
直觉:100 台服务器各自的响应时间可能乱七八糟,但它们的平均响应时间一定接近正态
Python 代码(正态分布 + 68-95-99.7):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| from scipy import stats import matplotlib.pyplot as plt import numpy as np
mu, sigma = 200, 30 norm_dist = stats.norm(mu, sigma)
x = np.linspace(mu - 4*sigma, mu + 4*sigma, 300) pdf = norm_dist.pdf(x)
plt.figure(figsize=(12, 6)) plt.plot(x, pdf, 'k-', linewidth=2)
colors = ['#2196F3', '#4CAF50', '#FF9800'] labels = ['68% (μ±1σ)', '95% (μ±2σ)', '99.7% (μ±3σ)'] for i, (mult, color, label) in enumerate(zip([1, 2, 3], colors, labels)): left, right = mu - mult*sigma, mu + mult*sigma x_fill = np.linspace(left, right, 200) plt.fill_between(x_fill, norm_dist.pdf(x_fill), alpha=0.3 - i*0.08, color=color, label=label)
plt.xlabel('响应时间 (ms)') plt.ylabel('概率密度') plt.title('API响应时间的正态分布 N(200, 30²)') plt.legend() plt.show()
prob_slow = 1 - norm_dist.cdf(300) print(f"响应时间超过300ms的概率: {prob_slow:.4f}") print(f"(即 {prob_slow*100:.2f}% 的请求会超时)")
|
指数分布 Exponential(λ)
事件之间的时间间隔
概率密度函数:$f(x) = \lambda e^{-\lambda x}$,x ≥ 0
生存函数:$P(X > t) = e^{-\lambda t}$
期望 $E(X) = 1/\lambda$
无记忆性:
$P(X > s+t \mid X > s) = P(X > t)$
已经等了 5 分钟没坏,再等 3 分钟坏的概率和一开始就等 3 分钟一样
直觉:服务器不会因为”运行了很久”就更容易崩溃(理想化假设)
应用场景:
服务器故障间隔时间
两次请求之间的间隔
安全事件间的时间间隔
Python 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| from scipy import stats import matplotlib.pyplot as plt import numpy as np
lam = 0.5 exp_dist = stats.expon(scale=1/lam)
x = np.linspace(0, 10, 300) pdf = exp_dist.pdf(x)
plt.figure(figsize=(10, 5)) plt.plot(x, pdf, 'r-', linewidth=2, label='PDF') plt.fill_between(x, pdf, alpha=0.3, color='red') plt.xlabel('时间间隔 (小时)') plt.ylabel('概率密度') plt.title(f'指数分布 Exp(λ={lam}):故障间隔时间')
x_fill = np.linspace(4, 10, 100) plt.fill_between(x_fill, exp_dist.pdf(x_fill), alpha=0.5, color='blue', label=f'P(X>4h) = {1-exp_dist.cdf(4):.3f}') plt.legend() plt.show()
s, t = 2, 3 p_conditional = (1 - exp_dist.cdf(s+t)) / (1 - exp_dist.cdf(s)) p_direct = 1 - exp_dist.cdf(t) print(f"P(X>{s+t}|X>{s}) = {p_conditional:.6f}") print(f"P(X>{t}) = {p_direct:.6f}") print(f"两者相等 → 无记忆性成立!")
|
对数正态分布 LogNormal
如果 ln(X) 服从正态分布,则 X 服从对数正态分布
特点:只取正值、右偏(有长尾)
直觉:大多数请求响应很快,但少数请求极慢——这就是对数正态
大数据应用:响应时间建模比正态分布更准确
分布之间的关系图谱
伯努利 → (重复n次) → 二项分布
二项分布 → (n→∞, p→0, np=λ) → 泊松分布
泊松分布(计数) ↔ 指数分布(间隔):同一枚硬币的两面
任何分布 → (样本均值, n→∞) → 正态分布(中心极限定理)
综合应用场景
安全方向
攻击事件建模:
每天遭受的攻击次数 → 泊松分布
两次攻击之间的间隔 → 指数分布
异常检测阈值:
正常流量建模为正态分布
超过 μ+3σ 的流量 → 告警(只有 0.15% 的正常流量会到这里)
暴力破解分析:
几何分布估算破解所需尝试次数
代码示例——异常检测:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import numpy as np from scipy import stats
np.random.seed(42) normal_traffic = np.random.normal(loc=1000, scale=150, size=1000)
attack_traffic = np.array([3000, 3500, 2800, 4000, 3200]) all_traffic = np.concatenate([normal_traffic, attack_traffic])
mu = np.mean(normal_traffic) sigma = np.std(normal_traffic) threshold = mu + 3 * sigma
anomalies = all_traffic[all_traffic > threshold] print(f"正常流量: μ={mu:.0f}, σ={sigma:.0f}") print(f"3σ阈值: {threshold:.0f}") print(f"检测到 {len(anomalies)} 个异常值: {anomalies}")
|
大数据方向
请求量建模:
每秒请求数 → 泊松分布
高峰期/低谷期分别建模
响应时间建模:
对数正态分布比正态分布更贴合实际
P99 延迟 = 99分位数
数据质量:
缺失值比例 → 二项分布
代码示例——响应时间分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import numpy as np from scipy import stats import matplotlib.pyplot as plt
np.random.seed(42) response_times = np.random.lognormal(mean=5, sigma=0.5, size=10000)
p50 = np.percentile(response_times, 50) p95 = np.percentile(response_times, 95) p99 = np.percentile(response_times, 99)
print(f"P50 (中位数): {p50:.1f} ms") print(f"P95: {p95:.1f} ms") print(f"P99: {p99:.1f} ms")
plt.figure(figsize=(10, 5)) plt.hist(response_times, bins=100, density=True, alpha=0.7, color='steelblue') for pval, label, color in [(p50,'P50','green'), (p95,'P95','orange'), (p99,'P99','red')]: plt.axvline(x=pval, color=color, linestyle='--', label=f'{label}={pval:.0f}ms') plt.xlabel('响应时间 (ms)') plt.ylabel('概率密度') plt.title('响应时间分布(对数正态)') plt.legend() plt.xlim(0, 600) plt.show()
|
后端方向
故障率分析(指数分布):
MTBF(平均故障间隔)= 1/λ
可用性 = MTBF / (MTBF + MTTR)
负载预测(正态/泊松):
根据历史数据拟合分布
预测峰值,做容量规划
灰度发布:
新版本错误率是否符合预期 → 二项分布检验
代码示例——容量规划:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from scipy import stats import numpy as np
lam = 500
capacity_needed = stats.poisson.ppf(0.999, lam) print(f"平均 QPS: {lam}") print(f"99.9% 时间不过载需要的容量: {capacity_needed:.0f} QPS") print(f"建议预留 buffer: {capacity_needed/lam:.2f}x 平均值")
capacity_9999 = stats.poisson.ppf(0.9999, lam) print(f"99.99% 不过载需要: {capacity_9999:.0f} QPS ({capacity_9999/lam:.2f}x)")
|
Python 综合实战:拟合数据到分布
给你一堆数据,怎么知道它服从什么分布?
方法1:直方图 + 理论曲线叠加
方法2:QQ 图(Quantile-Quantile Plot)
方法3:统计检验(Kolmogorov-Smirnov 检验)
综合代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import numpy as np from scipy import stats import matplotlib.pyplot as plt
np.random.seed(42) data = np.random.exponential(scale=2.0, size=500)
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
mu, std = stats.norm.fit(data) x = np.linspace(0, max(data), 200) axes[0].hist(data, bins=30, density=True, alpha=0.7) axes[0].plot(x, stats.norm.pdf(x, mu, std), 'r-', linewidth=2) axes[0].set_title(f'正态拟合: μ={mu:.2f}, σ={std:.2f}')
loc, scale = stats.expon.fit(data) axes[1].hist(data, bins=30, density=True, alpha=0.7) axes[1].plot(x, stats.expon.pdf(x, loc, scale), 'r-', linewidth=2) axes[1].set_title(f'指数拟合: λ={1/scale:.2f}')
shape, loc_ln, scale_ln = stats.lognorm.fit(data, floc=0) axes[2].hist(data, bins=30, density=True, alpha=0.7) axes[2].plot(x, stats.lognorm.pdf(x, shape, loc_ln, scale_ln), 'r-', linewidth=2) axes[2].set_title(f'对数正态拟合')
plt.tight_layout() plt.show()
fig, ax = plt.subplots(figsize=(6, 6)) stats.probplot(data, dist="norm", plot=ax) ax.set_title('QQ图:检验正态性\n(偏离直线越多,越不正态)') plt.show()
distributions = { '正态': stats.norm(*stats.norm.fit(data)), '指数': stats.expon(*stats.expon.fit(data)), '对数正态': stats.lognorm(*stats.lognorm.fit(data, floc=0)) }
print("Kolmogorov-Smirnov 检验结果:") print("-" * 45) for name, dist in distributions.items(): ks_stat, p_value = stats.kstest(data, dist.cdf) result = "✓ 不拒绝" if p_value > 0.05 else "✗ 拒绝" print(f"{name:8s}: KS={ks_stat:.4f}, p={p_value:.4f} → {result}")
|
练习题
题目1:二项分布应用
一个API的失败率是 2%,你连续调用 200 次
(a) 期望失败次数是多少?
(b) 恰好失败 5 次的概率?
(c) 失败超过 10 次的概率?(提示:用 1 - cdf(10))
参考答案:
1 2 3 4 5 6
| from scipy import stats n, p = 200, 0.02 dist = stats.binom(n, p) print(f"(a) E(X) = {n*p}") print(f"(b) P(X=5) = {dist.pmf(5):.6f}") print(f"(c) P(X>10) = {1 - dist.cdf(10):.6f}")
|
题目2:泊松分布 + 异常检测
你的服务平均每分钟收到 8 个请求
(a) 某分钟收到 15 个请求,这异常吗?(计算 P(X≥15))
(b) 设定告警阈值为 P(X≥k) < 0.01,k 应该是多少?
参考答案:
1 2 3 4 5 6 7
| from scipy import stats lam = 8 dist = stats.poisson(lam) print(f"(a) P(X>=15) = {1 - dist.cdf(14):.6f}")
k = dist.ppf(0.99) + 1 print(f"(b) 告警阈值 k = {k:.0f}")
|
题目3:指数分布 + 无记忆性
服务器平均每 4 小时故障一次(λ=0.25/小时)
(a) 2 小时内不故障的概率?
(b) 已经稳定运行了 3 小时,再撑 2 小时不故障的概率?(验证无记忆性)
参考答案:
1 2 3 4 5 6 7 8 9
| from scipy import stats lam = 0.25 dist = stats.expon(scale=1/lam) p_a = 1 - dist.cdf(2) print(f"(a) P(X>2) = {p_a:.4f}")
p_b = (1 - dist.cdf(5)) / (1 - dist.cdf(3)) print(f"(b) P(X>5|X>3) = {p_b:.4f}") print(f" 与P(X>2)相同: {abs(p_a - p_b) < 1e-10}")
|
题目4:正态分布 + 容量规划
服务响应时间服从 N(150, 40²) ms,SLA 要求 99% 的请求在 X ms 内返回
(a) X 应该设为多少?
(b) 如果优化后 σ 从 40 降到 20,X 变为多少?减少了多少?
参考答案:
1 2 3 4 5 6 7 8
| from scipy import stats
x_99 = stats.norm.ppf(0.99, loc=150, scale=40) print(f"(a) SLA 阈值: {x_99:.1f} ms")
x_99_new = stats.norm.ppf(0.99, loc=150, scale=20) print(f"(b) 优化后阈值: {x_99_new:.1f} ms") print(f" 减少了: {x_99 - x_99_new:.1f} ms")
|
题目5:综合——选择合适的分布
判断以下场景应该用什么分布建模,并说明理由:
(a) 每天新发现的安全漏洞数量
(b) 用户密码长度
(c) 两次系统崩溃之间的时间
(d) 1000次登录中成功的次数
(e) 单次登录是否成功
参考答案:
(a) 泊松分布——单位时间内的计数事件
(b) 正态分布——集中在某个均值附近,左右对称
(c) 指数分布——事件间隔时间
(d) 二项分布——n次独立试验中的成功次数
(e) 伯努利分布——单次试验,两种结果
本节小结
离散分布核心三兄弟:伯努利 → 二项 → 泊松
连续分布核心三姐妹:均匀 → 正态 → 指数
选分布的关键问题:
结果可数还是连续?
在数”次数”还是量”间隔”?
有没有固定的试验次数?
下一节 22-假设检验与AB测试 将用这些分布做推断