滑动窗口异常检测
滑动窗口异常检测
学习目标
读完本章后,你将能够:
- 理解基于均值-标准差的滑动窗口异常检测算法
- 实现时间序列的分组统计与多维度检测
- 设计峰值冷却间隔避免重复告警
- 处理冷启动问题和窗口大小选择
核心概念
异常检测的本质
异常检测回答一个简单问题:当前值是否显著偏离了正常模式?
算法步骤
对于每个新到的数据点 x_t: 1. 将 x_t 加入滑动窗口 2. 计算窗口内数据的均值 μ 和标准差 σ 3. 如果 x_t > μ + N × σ: 标记为异常 4. 清理窗口中过期的数据点标准差倍数(N)的选择:
| N 值 | 灵敏度 | 误报率 | 适用场景 |
|---|---|---|---|
| 2 | 高 | 较高(约 5%) | 快速检测、允许误报 |
| 3 | 中 | 低(约 0.3%) | 平衡检测 |
| 4+ | 低 | 极低 | 只关注极端异常 |
实现细节
均值与标准差的在线计算
def stats_for(data, skip_last: 0) data = data[0...(data.length - skip_last)] length = data.length.to_f return [0, 0] if length == 0
# 计算均值 mean = data.sum / length
# 计算标准差(总体标准差) variance = data.sum { |v| (v - mean)**2 } / length std_dev = Math.sqrt(variance)
[mean, std_dev]endskip_last 的作用:检测当前值是否异常时,排除当前值本身——用历史数据建立”正常”基线,再判断当前值是否偏离。
滑动窗口管理
窗口清理策略:
def cleanup(group) newest_time = memory['data'][group].last.last cutoff = newest_time - window_duration memory['data'][group].reject! { |_value, time| time <= cutoff }end高级功能
分组检测
当事件流包含多个维度的数据时,按维度分组独立检测:
分组的价值:不同组可能有不同的”正常”基线。北京的温度在 35°C 可能是正常的,而哈尔滨的 35°C 就是异常。
峰值冷却
冷却策略:在峰值发生后的一段时间内不再检测新峰值,避免连续告警。
def check_for_peak(group, event) # 如果上次峰值距今小于冷却间隔,跳过检测 if memory['peaks'][group].last < event.created_at.to_i - peak_spacing # 执行检测... endend冷启动保护
def check_for_peak(group, event) # 数据点不足时不检测,避免冷启动误报 return if memory['data'][group].length <= min_events # 执行检测...endmin_events 值 | 行为 |
|---|---|
| 4(默认) | 至少 4 个数据点后才开始检测 |
| 10+ | 更保守,需要更多历史数据 |
陷阱与对策
陷阱一:非正态分布
均值-标准差方法假设数据近似正态分布。对于偏态分布(如请求延迟),误报率会显著上升。
对策:
- 使用对数变换(
log(x))将偏态分布转换为近似正态 - 改用百分位方法(如 P99)替代均值-标准差
- 使用 ESD(Extreme Studentized Deviate)检验处理多异常值问题
陷阱二:窗口大小选择
| 窗口太小 | 窗口太大 |
|---|---|
| 基线不稳定,波动大 | 对变化的”正常”模式反应迟钝 |
| 误报率高 | 漏报率高 |
经验法则:窗口应覆盖至少一个完整的周期(如 24 小时、7 天),以便捕捉周期性变化。
陷阱三:多异常值问题
当窗口内存在多个异常值时,它们会拉高均值和标准差,导致后续异常无法被检测。
对策:
- 峰值冷却间隔限制已检测峰值的影响
- 使用
skip_last: 1排除当前值再计算统计量 - 使用迭代方法:检测并移除最显著异常,重新计算
设计取舍
均值-标准差 vs 其他方法
| 方法 | 复杂度 | 适用分布 | 多异常值 | 在线计算 |
|---|---|---|---|---|
| 均值-标准差 | O(n) | 近似正态 | 差 | 是 |
| 中位数-MAD | O(n) | 任意 | 好 | 是 |
| 百分位 | O(n log n) | 任意 | 好 | 是 |
| ESD | O(k×n) | 近似正态 | 好 | 部分 |
| Isolation Forest | O(n log n) | 任意 | 好 | 否 |
均值-标准差的优势:实现简单、计算高效、对于大多数 Agent 场景(Twitter 提及量、API 调用频率等)足够有效。
滑动窗口 vs 指数衰减
| 维度 | 滑动窗口 | 指数衰减 |
|---|---|---|
| 内存 | O(窗口大小) | O(1) |
| 响应速度 | 快(旧数据突然消失) | 平滑(旧数据逐渐减弱) |
| 实现复杂度 | 低 | 中 |
| 适用场景 | 有明确周期性的数据 | 无固定周期的数据 |
参考来源
- Anomaly Detection: A Survey — Chandola et al., ACM Computing Surveys, 2009
- Twitter AnomalyDetection — Twitter 开源的 R 语言异常检测包,使用 S-H-ESD 算法
- STL: Seasonal-Trend decomposition — 时间序列分解方法