4、统计方法基础:均值、方差、分位数、Z-Score 与箱线图在异常检测中的应用

4.1 为什么统计方法能检测异常?

异常检测说白了就一句话——找到那些「跟大部分数据不一样」的点。那怎么定义「不一样」呢?拍脑袋肯定不行,得靠统计量来说话。

我刚开始做数据分析时,总觉得异常检测就是设个上下限,超过就算异常。后来发现,没有均值、方差这些统计量打底,你根本解释不了「为什么这个值算异常」。统计方法的核心作用,就是给「常态」画个像,再给「偏离」量个尺。

下面这张图概括了本章要讲的核心方法体系,你先有个整体印象,后面咱们一个一个拆开聊。

统计异常检测方法体系 统计异常检测方法体系 原始数据输入 均值 (Mean) 方差 (Variance) 分位数 (Quantile) Z-Score 核心统计方法 箱线图 (Box Plot) 异常判定输出 各方法从不同维度量化 「常态」与「偏离程度」

从图里你能看到,原始数据进来之后,四个统计方法从不同角度去刻画数据。最后汇到箱线图做综合可视化,输出异常判定。下面咱们一个一个说清楚。

4.2 均值 — 数据的「重心」

均值就是算术平均,所有数据加起来除以个数。它描述的是数据的集中位置,异常检测里最基础的基准线。

但我得提醒你一句:均值对极端值极其敏感。我在项目中遇到过一回——监控电商平台的订单金额,大部分订单在 100~500 元之间,结果有一天有个大单冲到了 10 万,均值瞬间从 280 跳到 650。如果你拿这个均值去做异常检测,正常订单反而被判成异常了。

避坑指南: 我曾经因为没做数据清洗直接用均值做基线,导致误报率飙升到 40%。记住,用均值之前,先看看数据里有没有明显的离群点,或者考虑用截尾均值(去掉头尾后再平均)。
import numpy as np
data = [2, 3, 5, 7, 11, 13, 100]
mean = np.mean(data)
# 结果是 20.14,被 100 严重拉高
# 真实情况是大部分数据都在 2~13 之间

4.3 方差 — 数据的「离散度」

方差衡量的是数据围绕均值的波动程度。方差越大,数据越散;方差越小,数据越聚。标准差是方差的平方根,单位跟原始数据一致,用起来更直观。

在异常检测里,3σ原则是个经典用法——如果数据近似正态分布,那么大约 99.7% 的数据会落在均值 ±3 个标准差之内,落在外面的就有理由怀疑是异常。

我的习惯: 用方差做异常检测时,我会先算一个「移动方差窗口」。比如取最近 50 个点的方差,如果当前点的偏差超过 3σ,我就标记它。这种方法在时序数据上特别好用。
# 计算方差与标准差
var = np.var(data)   # 方差
std = np.std(data)   # 标准差
# 3σ 上下界
upper = mean + 3 * std
lower = mean - 3 * std

4.4 分位数 — 数据的「位置坐标」

分位数比均值更「扛造」。它把数据从小到大排好,然后在特定位置切一刀。最常用的是四分位数:Q1(25%)、Q2(中位数,50%)、Q3(75%)。

异常检测里有个非常经典的方法——IQR 规则:IQR = Q3 − Q1,正常范围是 [Q1 − 1.5×IQR, Q3 + 1.5×IQR],超出这个范围就算异常。

为什么分位数更稳健? 因为分位数只看排序位置,不管具体数值有多大。哪怕数据里混进一个 10 亿,Q1、Q3 也基本不动。我在做金融交易数据清洗时,首选就是 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
# 超出 bound 的点视为异常

4.5 Z-Score — 标准化的异常分数

Z-Score 告诉你「这个点偏离均值多少个标准差」。公式很简单:z = (x − μ) / σ。它的好处是把所有数据拉到同一把尺子上,不同量纲的特征也能直接比较。

一般取 |z| > 2 作为警告线,|z| > 3 作为强异常线。但我建议你根据自己的数据来调——我在做传感器异常检测时,数据波动小,取 2.5 就够用了;在做流量分析时,数据毛刺多,我取到 3.5 才敢报。

注意: Z-Score 假设数据大致服从正态分布。如果数据是双峰分布或者长尾分布,Z-Score 会失效。我曾经在一个数据竞赛里吃过这个亏——数据是左偏的,用 Z-Score 死活找不到异常,换成 IQR 一下就揪出来了。
z_scores = (np.array(data) - np.mean(data)) / np.std(data)
# |z| > 3 的点标记为异常
outliers = np.where(np.abs(z_scores) > 3)[0]

4.6 箱线图 — 可视化异常检测

箱线图把五数概括(最小值、Q1、中位数、Q3、最大值)画在一张图上,异常点直接以散点形式跑在 whisker 外面。我个人习惯是——拿到任何新数据集,先画个箱线图扫一遍。

为什么?因为肉眼一看就知道:数据有没有偏态?有没有离群点?中位数在什么位置?这些信息在 5 秒内就能获取。等你心里有了数,再选具体的统计方法去深挖。

import matplotlib.pyplot as plt
plt.boxplot(data, vert=False, showfliers=True)
# showfliers=True 会显示异常点(超出whisker的点)
plt.show()
一个小技巧: 箱线图的 whisker 长度默认是 1.5 倍 IQR。你可以根据业务场景调整——风控场景我缩到 1.2 倍,抓得更严;运维监控我放到 2 倍,减少误报。

4.7 综合对比与选型

方法多了就容易纠结:到底用哪个?我的建议是——不要只依赖一种方法,组合使用才是正道。下面这张表我经常贴在工位上,选型时扫一眼就清楚了。

方法 适用场景 优点 缺点 异常检测示例
均值 数据分布均匀,无极端值 计算极简,可解释性强 受极端值影响大 监控页面平均加载时间
方差 / 标准差 需要量化波动程度 反映数据离散度 无单位直观性,需结合均值 检测响应时间突发抖动
分位数 + IQR 偏态分布,含极端值 稳健,抗干扰能力强 忽略部分尾部信息 金融交易金额异常检测
Z-Score 近似正态分布 标准化后可跨特征比较 对非正态分布效果差 标准化异常评分板
箱线图 数据探索阶段 直观可视化,快速定位 无法精确量化 快速识别数据中的离群点

你想想看,均值告诉你「中心在哪」,方差告诉你「有多散」,分位数告诉你「位置稳不稳」,Z-Score 告诉你「偏离有多远」,箱线图把它们全部画出来。这五样工具组合在一起,异常检测的基本功就算打扎实了。

我的实操流程: 拿到数据 → 画箱线图全局扫一遍 → 用 IQR 或 Z-Score 做初筛 → 结合业务规则确认异常 → 输出检测报告。这套流程我在三个项目里跑过,稳定好用。
# 完整的组合检测示例
def detect_outliers(data, method='iqr'):
    if method == 'iqr':
        Q1, Q3 = np.percentile(data, [25, 75])
        iqr = Q3 - Q1
        return (data < Q1 - 1.5*iqr) | (data > Q3 + 1.5*iqr)
    elif method == 'zscore':
        z = (data - np.mean(data)) / np.std(data)
        return np.abs(z) > 3