跳到正文
异常检测:一个实用速览
文章 约 1 分钟
· 约 1 分钟 · 异常检测 · 数据科学 · 监控

异常检测:一个实用速览

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

异常检测听起来很高大上,但我的经验是:现实里 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 之外的点视为异常

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

交互 · 异常检测 同一条曲线,不同的检测器 在同一条 90 天的合成指标上,比较全局 z-score、滚动窗口和季节性残差三种规则。
第 90 天 第 1 天
方法
标记总数 0 落在置信带外的点
命中真异常 0 / 3 注入的异常中被找到的
误报 0 被误标的普通日子

实用建议

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

元问题

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