Skip to content
Anomaly Detection · 2025年5月18日 · 约 2 分钟

异常检测:一个实用速览

时间序列异常检测的实战指南。从最朴素的规则,到统计学方法。

异常检测听起来很高大上,但我的经验是:现实里 80% 的场景用异常简单的方法就能解决。

问题定义

你有一个指标 — 收入、注册、报错数,随便哪种 — 想知道什么时候出了异常。不是”数字涨了”,而是”数字比预期涨得多”。

方法一:简单 Z-score

把今天的值与历史均值、标准差对比:

z_score = (current_value - historical_mean) / historical_std
is_anomaly = abs(z_score) > 3

适用:稳定、没有强季节性的指标。

局限:处理不了趋势和周内模式。

方法二:滚动统计

用滚动窗口让基线自适应:

rolling_mean = df["metric"].rolling(window=28).mean()
rolling_std = df["metric"].rolling(window=28).std()
z_score = (df["metric"] - rolling_mean) / rolling_std

适用:有缓慢趋势的指标。

局限:仍处理不好季节性。

方法三:季节性分解

把时间序列拆成趋势、季节、残差,对残差做检测:

from statsmodels.tsa.seasonal import seasonal_decompose

result = seasonal_decompose(df["metric"], period=7)
residuals = result.resid
# 对残差做 z-score

适用:周/月级别有明显周期的指标。

方法四:Prophet

Facebook Prophet 自带不确定区间:

from prophet import Prophet

model = Prophet(interval_width=0.99)
model.fit(df)
forecast = model.predict(df)
# 落在 yhat_upper/yhat_lower 之外的点视为异常

适用:复杂季节性、节假日效应。

实用建议

  1. 从简单开始:Z-score 能解决的问题比你想的多。我通常就从这里起步。
  2. 调阈值:3σ 是起点不是铁律。根据你能容忍的误报率调整。
  3. 处理缺失值:检测器最烦数据有洞,填补要讲究。
  4. 警报疲劳是真的:宁可漏报一些,也别天天喊狼来了。这是血泪经验。
  5. 先调查再报警:很多”异常”其实有平平无奇的原因。

元问题

异常检测最难的从来不是算法 — 而是定义什么样的异常值得采取行动。从”看到这条告警我们会做什么?“倒推阈值。如果答案是”什么也不做”,那也许这条告警根本不必存在。