跳到内容

7.3 异常检测、Novelty 与阈值:异常分数只有进入处置流程才有意义

预言厅每天产生数十万条任务记录,人工只能复核很少一部分。阿花没有要求模型“找出所有奇怪的点”,而是给出一个更具体的约束:每天最多调查 200 条,漏掉高损失故障的代价远高于检查普通记录。

这使异常检测成为一个决策问题。模型先产生相对分数,阈值再结合告警预算、错误成本和随时间变化的基准率决定谁被处理。

本课目标

  • 区分 outlier detection 与 novelty detection;
  • 理解 Isolation Forest、LOF 与稳健协方差的假设;
  • 分开异常分数、阈值和业务处置;
  • 在标签稀少、延迟和污染存在时设计评估;
  • 处理时间漂移、群组差异和反馈效应。

1. “异常”必须由场景定义

罕见不等于有害,常见也不等于正常。一次超大订单可能是欺诈,也可能是合法大客户;一台设备的低温可能正常,但对另一型号是故障。

先写清:

  • entity:给用户、交易、设备还是时间窗口打分;
  • cutoff:预测时能看到哪些字段;
  • anomaly event:什么结果值得行动;
  • horizon:多长时间内验证结果;
  • action/capacity:调查、限流、停机或仅记录;
  • label delay:多久后才知道真假。

没有这些定义,“离群”只是几何描述。

2. Outlier 与 novelty 是两种训练条件

Outlier detection

训练样本中已混有少量异常。模型尝试找出低密度、易隔离或偏离主体结构的点。fit_predict(X) 常用于同一 snapshot 的探索。

Novelty detection

训练数据被认为近似代表正常状态,目标是判断未来新样本是否偏离正常分布。应在 baseline period/正常群体上 fit,再对未见数据 predict/打分。

两者都可能被称为 anomaly detection,但 API 和评估不同。把污染训练集当纯正常 baseline,会让模型把异常模式学成正常;反过来,把训练样本上的 outlier 标签当未来部署性能也会过于乐观。

3. Isolation Forest 为什么用路径长度

Isolation Forest 重复构造随机树:随机选择特征,再在该特征当前范围内随机选择切分值。一个样本从根到被隔离所需的路径越短,通常越容易被视为异常。

直觉来自异常点常处于稀疏/边缘区域,较少随机切分就能单独分开。多棵树平均路径以降低随机波动。

它不是监督随机森林:分裂不优化标签或 Gini。高维无关特征、成群异常、类别编码和分布漂移仍会破坏效果。

4. 从分数到验证阈值

不同库的 score 正负方向可能相反,必须用最小测试确认。scikit-learn 的 IsolationForest.score_samples 越大通常越正常,因此可取负号得到“越大越异常”的统一分数:

python
import numpy as np
from sklearn.ensemble import IsolationForest

detector = IsolationForest(
    n_estimators=400,
    max_samples="auto",
    contamination="auto",
    random_state=42,
    n_jobs=-1,
)
detector.fit(X_train)

valid_anomaly_score = -detector.score_samples(X_valid)

# 若暂无可靠标签,可先按人工复核容量定义候选阈值。
# 这表示“告警预算约 1%”,不表示真实异常率就是 1%。
threshold = np.quantile(valid_anomaly_score, 0.99)

test_anomaly_score = -detector.score_samples(X_test)
test_alert = test_anomaly_score >= threshold

若 validation 有成熟标签,应按成本、precision/recall 或每天 top-$K$ 容量选阈值。Test 只用于冻结后的最终评估。

contamination 主要用于把连续 score 转成训练分布中的决策阈值。把它设为 0.01 不会让模型知道业务真实异常率,也不会保证 1% 告警都是真异常。

5. LOF 比较局部密度

Local Outlier Factor(LOF)比较样本的局部可达密度与其邻居密度。一个点即使处在全局稀疏区域,只要邻居也同样稀疏,可能仍属正常;比周围邻居明显更孤立时,LOF 才高。

n_neighbors 决定“局部”的尺度。太小会对噪声敏感,太大又接近全局密度判断。距离 metric、缩放和高维近邻质量同样关键。

scikit-learn 中要特别区分两种模式:

  • 默认 novelty=False:用于训练 snapshot 的 outlier detection,调用 fit_predict,训练分数在 negative_outlier_factor_
  • novelty=True:在基准数据 fit 后给新样本调用 predictdecision_functionscore_samples,不要把这些方法用于训练样本并与默认模式结果混比。
python
from sklearn.neighbors import LocalOutlierFactor

novelty_detector = LocalOutlierFactor(
    n_neighbors=30,
    contamination="auto",
    novelty=True,
)
novelty_detector.fit(X_train_normal)
new_anomaly_score = -novelty_detector.score_samples(X_new)

6. 其他方法各自带着假设

Robust covariance / Elliptic Envelope

用稳健位置与协方差估计 Mahalanobis distance,适合主体数据近似单峰椭球/Gaussian 的场景。多峰、非线性流形或 $p$ 接近/超过 $n$ 时要谨慎。

One-Class SVM

学习包围正常数据的边界,kernel 和带宽决定形状。它对尺度和超参数敏感,大样本 kernel 训练成本也高。

Reconstruction error

PCA/autoencoder 在正常数据上训练,以重构误差打分。若模型容量过强,可能连异常也重构良好;若正常状态多样,少数正常群体又可能被误报。

规则与监督模型

明确不可能条件常适合规则。若已有足够成熟标签,supervised rare-event model 通常能更直接优化业务目标;无监督分数可以作为一个 feature/baseline,而不是身份信仰。

7. 前处理会定义谁“离群”

  • 未缩放数值会让大单位列主导距离/切分;
  • one-hot 稀有类别可能天然显得孤立;
  • 缺失填充值可形成假的高密度点;
  • 使用未来窗口统计会产生时间泄漏;
  • 全量数据先标准化会让未来分布影响基准。

训练、validation、test 按时间/实体切分,所有 transform 只在对应训练段拟合。对周期性、季节性系统,可按 hour-of-week、设备型号等建条件基准,而不是用一个全局“正常”。

8. 标签稀少时怎样评估

有成熟标签时优先报告:

  • precision-recall curve,而不是只看 ROC AUC;
  • recall at daily alert budget/top-$K$;
  • 每次调查成本、漏报损失与净收益;
  • time-to-detect;
  • 按群体、设备型号和时间的误报率。

没有完整标签时可以:

  • 对 top-ranked 样本做 blinded expert review;
  • 追踪后续故障/退款/人工处置等 delayed outcomes;
  • 用历史已知事件做 time-backtest;
  • 注入受控且符合机制的 fault,验证最低检测能力;
  • 报告 review sample 的选择偏差与未标记不确定性。

随机制造极端点只证明模型能找到这种极端,不代表能发现真实异常。Synthetic anomaly 不能代替生产 backtest。

9. 告警会改变后续数据

模型上线后,被告警样本得到更多调查与标签,未告警样本可能长期未知。直接用这些标签重训会产生 verification/selection bias。

治理措施包括:

  • 在告警外保留随机审计样本;
  • 记录 score、threshold、模型版本和处置结果;
  • 分开“未调查”与“确认正常”;
  • 监控告警量、score 分布、缺失率与调查命中率;
  • 设定阈值降级、模型失效和人工接管规则。

攻击者还能适应公开规则,欺诈/安全场景需把 adversarial adaptation 纳入验证。

10. 漂移下重新校准阈值

设备更新、季节变化和业务增长会改变正常分布。固定 score threshold 可能突然淹没调查队列或停止告警。

监控应区分:

  • covariate drift:输入与 embedding 变化;
  • score drift:异常分数整体移动;
  • alert-rate drift:阈值以上比例变化;
  • outcome drift:同一分数的真实风险变化;
  • capacity drift:人工每天能处理多少。

定期重训并不自动安全。每次更新都要回放稳定窗口、保留 incident cases、比较群体影响,并版本化阈值。

常见误区

  • 异常就是距离均值最远:局部密度、条件群体和任务语义都可能更重要。
  • contamination 是模型学到的真实异常率:它主要控制分数切点。
  • 无标签就无法评估:可用审计、延迟结果、backtest 和容量指标,但要披露局限。
  • 训练集分数好就能检测未来 novelty:训练条件与 API 不同。
  • 告警越多越安全:容量受限时会降低 precision 并造成处置拥堵。

练习

  1. 为交易或设备场景写出 entity、cutoff、horizon、action 与 label delay。
  2. 验证 IsolationForest 各评分 API 的方向和 threshold 关系。
  3. 比较 LOF 的 outlier 与 novelty 模式,避免在错误样本上调用方法。
  4. 以每日 200 条告警预算比较 precision、recall 和 time-to-detect。
  5. 设计一组告警外随机审计样本,估计未告警区域的漏报。

小结

异常检测先学习相对正常结构,再把 score 交给阈值和处置流程。Isolation Forest 偏好易随机隔离的点,LOF 比较局部密度,其他方法依赖椭球、边界或重构假设。可靠系统还需要时间切分、调查容量、反馈偏差和漂移监控。

下一章进入模型评估:把指标、交叉验证、超参数搜索和最终测试组织成一套不会相互污染的协议。

Built with VitePress | Software Systems Atlas