引言
欺诈交易、服务器故障、设备损坏——这些「异常」在数据里只占极小比例,却是最有价值的部分。异常检测(Anomaly Detection)的目标不是「分好多数类」,而是找出少数异常。它与类别不平衡问题紧密相关:异常极稀少、正负比例悬殊。本文覆盖从统计方法到隔离森林、AutoEncoder 的完整武器库,以及不平衡学习的处理套路与评估指标。
前置:/ml-model-evaluation/(评估与混淆矩阵)、/ml-supervised-classification/(分类与不平衡)、/ml-deep-learning-advanced/(神经网络基础)。
目录
- 1. 异常检测问题定义与场景
- 2. 统计方法:Z-score、IQR 与 MAD
- 3. 无监督方法总览
- 4. 隔离森林:用「好切」找异常
- 5. One-Class SVM 与 Local Outlier Factor
- 6. AutoEncoder:重构误差即异常分
- 7. 类别不平衡:重采样与代价敏感
- 8. 阈值选择:权衡召回与误报
- 9. 评估与落地:精度陷阱
- 10. 速查表与一句话记忆
- 延伸阅读
1. 异常检测问题定义与场景
1.1 什么是异常
异常 = 与绝大多数数据「行为显著不同」的点。三类典型:
| 类型 | 例子 |
|---|---|
| 点异常 | 一笔金额 100 万的转账 |
| 上下文异常 | 深夜的高频登录 |
| 集体异常 | 一批账号同时小额转账 |
1.2 与分类的区别
- 分类:有标签、样本均衡
- 异常检测:标签稀少/缺失、极度不均衡、异常「不是一类而是很多种」
记忆:异常检测找少数「另类」点,异常种类多且标签少;欺诈/故障/设备监控是高频场景。
2. 统计方法:Z-score、IQR 与 MAD
2.1 Z-score
偏离均值几个标准差:
import numpy as np
z = np.abs((x - x.mean()) / x.std())
outliers = z > 3 # 超过 3 个标准差
缺点:受异常本身污染均值和标准差(masking)。
2.2 IQR 与 MAD(更稳健)
# IQR:四分位距
q1, q3 = np.percentile(x, [25, 75]); iqr = q3 - q1
outliers = (x < q1 - 1.5*iqr) | (x > q3 + 1.5*iqr)
# MAD:中位数绝对偏差,比标准差更抗异常
mad = np.median(np.abs(x - np.median(x)))
threshold = 3 * 1.4826 * mad
outliers = np.abs(x - np.median(x)) > threshold
记忆:Z-score 快但易被异常污染;IQR/MAD 用分位数和中位数更稳健,异常检测首选稳健统计量。
3. 无监督方法总览
| 方法 | 思路 | 适用 |
|---|---|---|
| 隔离森林 | 好切=易隔离 | 高维表格数据 |
| OneClassSVM | 找边界超平面 | 中等维度、流形 |
| LocalOutlierFactor | 邻域密度比较 | 局部密度差异 |
| AutoEncoder | 重构误差 | 高维/图像/序列 |
无监督 = 不需要标签,靠「结构差异」定义异常。
记忆:无监督异常检测四类——隔离森林/OneClassSVM/LOF/AutoEncoder,各有擅长的数据结构。
4. 隔离森林:用「好切」找异常
4.1 直觉
随机切数据:异常点分布稀疏,几下就被切出来;正常点密集,需要很多刀。
正常点:随机树中路径很深(难隔离)
异常点:随机树中路径很浅(易隔离)
异常分数 = 平均路径深度(越浅越异常)
4.2 代码
from sklearn.ensemble import IsolationForest
iso = IsolationForest(
n_estimators=200, contamination=0.01, # 预期异常比例
random_state=42)
iso.fit(X) # 无标签!
scores = iso.decision_function(X) # 越低越异常
pred = iso.predict(X) # -1 异常 / 1 正常
4.3 特点
- 快、可并行、高维尚可
contamination需按业务预估异常率- 对正常模式固定的数据效果好
记忆:隔离森林用随机切分的路径深度找异常——异常易隔离路径浅;contamination 设预期异常率,predict 返回 -1/1。
5. One-Class SVM 与 Local Outlier Factor
5.1 One-Class SVM
在高维空间找「包含大部分数据的边界」,边界外即异常:
from sklearn.svm import OneClassSVM
ocsvm = OneClassSVM(kernel='rbf', gamma=0.1, nu=0.01) # nu≈异常比例
ocsvm.fit(X)
pred = ocsvm.predict(X) # -1 异常
5.2 Local Outlier Factor(LOF)
比较样本与其近邻的局部密度:密度远低于邻域 = 异常:
from sklearn.neighbors import LocalOutlierFactor
lof = LocalOutlierFactor(n_neighbors=20, contamination=0.01)
pred = lof.fit_predict(X) # -1 异常(自监督,无 fit 分数)
记忆:OneClassSVM 用边界超平面圈正常区;LOF 比较局部密度;二者对数据尺度敏感,先标准化。
6. AutoEncoder:重构误差即异常分
6.1 思路
用正常数据训练一个自编码器:正常样本重构好(误差小),异常样本重构差(误差大)——重构误差就是异常分数。
6.2 PyTorch 实现骨架
import torch, torch.nn as nn
class AE(nn.Module):
def __init__(self, in_dim, h_dim=32):
super().__init__()
self.enc = nn.Sequential(nn.Linear(in_dim, h_dim*2), nn.ReLU(),
nn.Linear(h_dim*2, h_dim))
self.dec = nn.Sequential(nn.Linear(h_dim, h_dim*2), nn.ReLU(),
nn.Linear(h_dim*2, in_dim))
def forward(self, x):
return self.dec(self.enc(x))
# 只在正常数据上训练,最小化 MSE
model = AE(X_normal.shape[1])
# ... 训练循环 ...
with torch.no_grad():
rec_err = torch.mean((model(X_all) - X_all)**2, dim=1) # 异常分
6.3 变体
- 卷积自编码器:图像异常检测
- LSTM 自编码器:时间序列异常
- VAE:用重建似然替代 MSE
记忆:AutoEncoder 只在正常数据上训练,重构误差大的样本判异常;配卷积/LSTM 可做图像/时序异常。
7. 类别不平衡:重采样与代价敏感
7.1 数据层面:重采样
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
sm = SMOTE(random_state=42) # 少数类合成过采样
X_res, y_res = sm.fit_resample(X, y)
# 或 combined = SMOTEENN(...) 过采样+清洗
7.2 算法层面:代价敏感
# 给少数类更高权重
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(class_weight='balanced_subsample', random_state=42)
7.3 阈值层面
不用默认 0.5 概率阈值,按业务要求调
阈值 → 用验证集上 Precision/Recall 权衡选
记忆:不平衡三条路——SMOTE 重采样(数据)、class_weight 加权(算法)、按业务调概率阈值(决策)。
8. 阈值选择:权衡召回与误报
8.1 Precision-Recall 曲线选点
from sklearn.metrics import precision_recall_curve
precision, recall, thresholds = precision_recall_curve(y_val, scores)
# 选业务可接受的召回/精度组合
# 如欺诈:宁可误报也要召回高 → 选低阈值
8.2 业务目标驱动
| 场景 | 侧重点 |
|---|---|
| 欺诈风控 | 高召回(宁误报不漏) |
| 设备故障 | 高精度(避免停产误操作) |
| 质量检测 | 平衡 + 人工复核 |
记忆:阈值别用 0.5 默认——用 PR 曲线按业务选点;欺诈要高召回、设备要高精度。
9. 评估与落地:精度陷阱
9.1 精度陷阱
异常只有 1%,瞎猜「全部正常」精度 99%——精度完全无意义。异常检测看:
- Precision / Recall / F1(对异常类)
- PR-AUC(类别极不均衡时的首选)
- 业务成本(漏一个损失 vs 误报一个成本)
9.2 落地要点
# 评估只看异常类的指标
from sklearn.metrics import classification_report
print(classification_report(y_test, pred, labels=[1], target_names=['anomaly']))
- 用真实分布评估(别在过采样后的数据上测)
- 监控:线上定期重训练,漂移会摧毁异常检测
- 与人工复核闭环:标注可疑样本回炉
记忆:异常检测别信精度——异常占比低时全猜正常也 99% 精度;看异常类的 PR/F1 与 PR-AUC,用业务成本定阈值,线上要监控漂移并人工复核闭环。
10. 速查表与一句话记忆
| 方法 | 类型 | 关键点 |
|---|---|---|
| Z-score | 统计 | 受污染,快 |
| IQR/MAD | 统计 | 稳健 |
| 隔离森林 | 无监督 | 路径深度、contamination |
| OneClassSVM | 无监督 | nu≈异常比例 |
| LOF | 无监督 | 局部密度 |
| AutoEncoder | 深度 | 重构误差 |
| SMOTE | 数据 | 少数类合成 |
| class_weight | 算法 | 代价敏感 |
| PR 曲线 | 评估 | 按业务选阈值 |
一句话记忆:异常检测找少数「另类」点——统计方法用 IQR/MAD(比 Z-score 稳健),无监督方法用隔离森林(路径深度)、OneClassSVM(边界)、LOF(密度)、AutoEncoder(重构误差);类别不平衡用 SMOTE 重采样 + class_weight 加权 + 按业务调阈值;评估别信精度(全猜正常也 99%),看异常类的 Precision/Recall/F1 与 PR-AUC,线上监控漂移、人工复核闭环。
延伸阅读
- /ml-model-evaluation/ — 评估指标与交叉验证
- /ml-supervised-classification/ — 分类与类别不平衡
- /ml-deep-learning-advanced/ — 神经网络与自编码器基础
- /ml-feature-engineering/ — 异常检测特征构建
- /ml-model-deployment/ — 检测模型上线与监控
- [[ai-ml]] — 算法原理深度专题
- scikit-learn 异常检测文档
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。