4. 统计学方法(一):3-Sigma原则、Z-Score方法、箱线图法(IQR)
聊到异常检测,很多人第一反应就是上机器学习模型。但说实话,我做了这么多年实战项目,最常用的反而是最基础的统计学方法。为什么?因为简单、可解释、还特别快。
今天咱们就聊聊三个经典工具:3-Sigma、Z-Score 和箱线图。它们都是基于数据分布来做判断的。说白了,就是看看哪些点「不合群」。
核心思想:异常点就是那些偏离正常分布太远的点。统计学给了我们一把尺子,量一量就知道谁出格了。
4.1 3-Sigma 原则
3-Sigma 原则,也叫拉依达准则。它假设数据服从正态分布。嗯,这里要注意——这个假设很关键。
正态分布有个特性:约 68% 的数据落在均值±1个标准差内,95% 落在±2个标准差内,99.7% 落在±3个标准差内。那剩下的 0.3% 呢?就是咱们要找的异常点。
判断规则很简单:
- 数据点与均值的距离 > 3倍标准差 → 异常
- 数据点与均值的距离 ≤ 3倍标准差 → 正常
我在项目中遇到过这样的情况:某传感器采集的温度数据,用 3-Sigma 一筛,发现几个点明显偏离。后来排查发现是传感器接触不良。你看,一个简单的统计规则,直接定位了硬件问题。
避坑指南:我曾经在一个非正态分布的数据集上硬套 3-Sigma,结果误报率高达 30%。后来才意识到,数据偏态严重时,3-Sigma 会失效。所以用之前,先画个直方图看看分布形态。
4.2 Z-Score 方法
Z-Score 其实是 3-Sigma 的标准化版本。它把原始数据转换成标准分数,公式很简单:
Z = (x - μ) / σ
其中 x 是原始值,μ 是均值,σ 是标准差。Z 值表示数据点偏离均值多少个标准差。
判断标准:
- |Z| > 3 → 异常(对应 3-Sigma)
- |Z| > 2 → 可疑点,需要关注
- |Z| ≤ 2 → 正常
你想想看,Z-Score 的好处是什么?它把不同量纲的数据统一到一个尺度上。比如你同时监控温度和压力,温度单位是摄氏度,压力是帕斯卡。直接用原始值没法比,但转成 Z-Score 后,就能放在一起分析了。
我个人习惯在数据预处理阶段先算 Z-Score,然后设定阈值。阈值怎么定?我一般先看业务容忍度。比如金融交易中,|Z|>2 就标记为可疑,因为漏掉一笔欺诈的代价太高了。
小技巧:如果数据量小(比如少于 30 个样本),Z-Score 的可靠性会下降。这时候我建议用箱线图法,它对样本量不敏感。
4.3 箱线图法(IQR)
箱线图法不依赖正态分布假设。它基于四分位数,说白了就是看数据的「中间段」和「两端」的关系。
核心概念:
- Q1(第一四分位数):数据从小到大排列,25% 位置的值
- Q3(第三四分位数):数据从小到大排列,75% 位置的值
- IQR(四分位距):IQR = Q3 - Q1
- 异常判定:数据点 < Q1 - 1.5×IQR 或 > Q3 + 1.5×IQR
为什么用 1.5 倍?这是统计学前辈们总结的经验值。如果你想要更严格的筛选,可以用 3 倍 IQR。我在做工业质检项目时,就用了 3 倍 IQR,因为产品瑕疵容忍度极低。
箱线图法的优势很明显:
- 不要求数据服从特定分布
- 对极端值不敏感(均值会被极端值拉偏,但中位数不会)
- 可视化直观,一眼就能看出异常点
实战对比:我曾经处理过一组电商订单金额数据,分布严重右偏(大部分订单几十块,偶尔有上万的)。用 3-Sigma 筛,那些上万的大单全被判为异常。但用箱线图法,只有真正离谱的(比如 Q3+3×IQR 之外的)才被标记。哪个更合理?显然是箱线图法。
4.4 三种方法对比
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 3-Sigma | 数据近似正态分布 | 计算简单,理论成熟 | 对非正态分布失效 |
| Z-Score | 多维度数据标准化后对比 | 统一量纲,阈值可调 | 同样依赖正态假设 |
| 箱线图法 | 任意分布,小样本 | 鲁棒性强,可视化好 | 对 IQR 倍数选择敏感 |
4.5 知识体系图
下面这张图帮你理清这三种方法的关系和适用场景:
4.6 代码实战
光说不练假把式。下面我用 Python 演示这三种方法:
import numpy as np
import pandas as pd
# 生成示例数据(包含异常点)
np.random.seed(42)
data = np.random.normal(100, 15, 1000)
data = np.append(data, [200, 210, 50, 45]) # 加入4个异常点
# 方法1:3-Sigma
mean = np.mean(data)
std = np.std(data)
sigma_3_upper = mean + 3 * std
sigma_3_lower = mean - 3 * std
anomalies_3sigma = data[(data > sigma_3_upper) | (data < sigma_3_lower)]
# 方法2:Z-Score
z_scores = (data - mean) / std
anomalies_zscore = data[np.abs(z_scores) > 3]
# 方法3:箱线图法(IQR)
Q1 = np.percentile(data, 25)
Q3 = np.percentile(data, 75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
anomalies_iqr = data[(data < lower_bound) | (data > upper_bound)]
print(f"3-Sigma 发现异常点: {len(anomalies_3sigma)} 个")
print(f"Z-Score 发现异常点: {len(anomalies_zscore)} 个")
print(f"箱线图法发现异常点: {len(anomalies_iqr)} 个")
我的建议:实际项目中,别只用一种方法。我通常先用箱线图法做快速筛查,再用 Z-Score 做精细分析。两种方法结果一致的点,基本可以确定是异常。如果结果不一致,那就需要结合业务逻辑来判断了。
好了,这三种方法讲完了。它们虽然基础,但非常实用。下次遇到异常检测问题,别急着上深度学习,先试试这些统计方法——说不定就够用了。