第四章 正态分布与3σ原则

说起异常检测,有个绕不开的东西——正态分布。我刚开始做数据清洗时,一上来就想着上机器学习,结果被老板骂了一顿:“你连数据长什么样都不看,调啥模型?”后来我才明白,很多场景下,一个简单的正态分布假设就能搞定七八成的异常问题。

先记住这句话: 如果数据近似正态分布,3σ就是最直觉、最快速的异常判定边界。

正态分布的特性

正态分布,也叫高斯分布。它的概率密度函数长这样:

f(x) = (1 / (σ * √(2π))) * e^[-(x - μ)² / (2σ²)]

看着唬人,但核心就俩参数:均值 μ(决定中心位置)和标准差 σ(决定胖瘦)。

  • 对称——以μ为中心左右对称。
  • 集中——大部分数据落在μ附近,离μ越远概率越低。
  • 可量化——68-95-99.7 法则,也就是咱们说的3σ。

我习惯先画个直方图看一眼。如果数据呈现“钟形”,我就会放心地用正态分布来建模。但注意:不是所有数据都服从正态分布。我在一个电商项目里见过用户行为时长数据——那是长尾分布,硬套3σ会漏掉大量真正的异常。

区间 覆盖比例 含义
[μ - σ, μ + σ] 约68% 常见值,正常波动范围
[μ - 2σ, μ + 2σ] 约95% 还算正常,需要留意边缘
[μ - 3σ, μ + 3σ] 约99.7% 大概率正常,之外的极端可疑

这张表我当年背得滚瓜烂熟。说实话,真正做项目时我没死记,直接用公式算Z-score更省事。

注意: 小样本(比如 n < 30)下正态性未必成立,3σ的判断可能会失效。我建议先用Shapiro-Wilk检验确认正态性,再决定是否用3σ。

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σ原则的具体步骤是这样的:

  1. 计算样本均值和标准差。
  2. 对每个数据点计算 |x - μ| / σ。
  3. 如果比值 > 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σ异常判定流程 计算 μ 和 σ 计算每个点的 Z-score |Z| ≤ 3 → 正常值 |Z| > 3 → 异常值 剔除异常值,重新计算 μ 和 σ 迭代一次或两次,直到收敛

这个迭代流程我用了很多年。特别是在时间序列的实时异常检测中,我会用一个滑动窗口不断更新 μ 和 σ,效果比固定阈值好得多。

一句话总结: 3σ不是万能药,但在正太假设成立、异常比例不高、并且计算资源有限的情况下,它是性价比最高的异常检测方案。

最后说一句:别把3σ和“统计学显著性”搞混。很多人问我 “3σ对应p值多少?” 其实这只是经验边界,严格来说单侧概率约0.00135,但异常检测不是假设检验,不用纠结精确的p值。够用就好。