第四章 正态分布与3σ原则
说起异常检测,有个绕不开的东西——正态分布。我刚开始做数据清洗时,一上来就想着上机器学习,结果被老板骂了一顿:“你连数据长什么样都不看,调啥模型?”后来我才明白,很多场景下,一个简单的正态分布假设就能搞定七八成的异常问题。
正态分布的特性
正态分布,也叫高斯分布。它的概率密度函数长这样:
f(x) = (1 / (σ * √(2π))) * e^[-(x - μ)² / (2σ²)]
看着唬人,但核心就俩参数:均值 μ(决定中心位置)和标准差 σ(决定胖瘦)。
- 对称——以μ为中心左右对称。
- 集中——大部分数据落在μ附近,离μ越远概率越低。
- 可量化——68-95-99.7 法则,也就是咱们说的3σ。
我习惯先画个直方图看一眼。如果数据呈现“钟形”,我就会放心地用正态分布来建模。但注意:不是所有数据都服从正态分布。我在一个电商项目里见过用户行为时长数据——那是长尾分布,硬套3σ会漏掉大量真正的异常。
| 区间 | 覆盖比例 | 含义 |
|---|---|---|
| [μ - σ, μ + σ] | 约68% | 常见值,正常波动范围 |
| [μ - 2σ, μ + 2σ] | 约95% | 还算正常,需要留意边缘 |
| [μ - 3σ, μ + 3σ] | 约99.7% | 大概率正常,之外的极端可疑 |
这张表我当年背得滚瓜烂熟。说实话,真正做项目时我没死记,直接用公式算Z-score更省事。
Z-score 原理
Z-score 其实就是“数据点离均值有几个标准差”。公式特别简单:
Z = (x - μ) / σ
Z 的值越大,说明这个点越“异常”。我通常这样看:
- |Z| ≤ 2 → 正常数据,落在95%区间内。
- 2 < |Z| ≤ 3 → 可疑,需要人工核查。
- |Z| > 3 → 极有可能异常,直接标记。
我有个血泪教训:有一回做传感器异常检测,原始数据里混了几个野值,导致均值和标准差被严重拉偏。这时候算出来的Z-score全都不正常——因为均值和标准差本身已经被污染了。后来我改用中位数和MAD(中位差)来替代,才稳住。所以用Z-score前,记得先做一次粗筛,或者直接用稳健统计量。
兜底策略: 如果数据明显偏态,别硬套Z-score。换成 稳健Z-score(基于中位数和MAD),公式是 Z_MAD = 0.6745 * (x - median) / MAD。这个我试过,抗住10%的污染都没问题。
基于3σ的异常判定
实际落地时,3σ原则的具体步骤是这样的:
- 计算样本均值和标准差。
- 对每个数据点计算
|x - μ| / σ。 - 如果比值 > 3,标记为异常。
代码实现也简单,我贴一段Python示例:
import numpy as np
def detect_outliers_3sigma(data):
mu = np.mean(data)
sigma = np.std(data, ddof=1) # 样本标准差
threshold = 3 * sigma
lower = mu - threshold
upper = mu + threshold
outliers = [x for x in data if x < lower or x > upper]
return outliers, lower, upper
注意这里用了 ddof=1,也就是用样本标准差而非总体标准差。为什么?因为咱们拿到的通常是样本,不是全部人口。用 ddof=0 会低估标准差,导致异常漏判。我之前就因为这个吃过亏——在生产流水线上,用总体标准差算出来的3σ边界偏窄,放过了不少坏品,差点被工艺部门投诉。
另外,3σ判定对异常点的数量非常敏感。如果异常比例超过5%,3σ边界就不准了。我建议先用3σ标记一轮,把极端值剔除后重新计算 μ 和 σ,再跑第二轮。这叫“迭代3σ”,效果会好很多。
这个迭代流程我用了很多年。特别是在时间序列的实时异常检测中,我会用一个滑动窗口不断更新 μ 和 σ,效果比固定阈值好得多。
最后说一句:别把3σ和“统计学显著性”搞混。很多人问我 “3σ对应p值多少?” 其实这只是经验边界,严格来说单侧概率约0.00135,但异常检测不是假设检验,不用纠结精确的p值。够用就好。