异常值检测算法
1. 基于分布的异常检测
1.1 3σ准则 (3-Sigma Rule)
原理:基于正态分布假设,认为距离均值3个标准差之外的数据点为异常值
数学表达式:
python
1 | def three_sigma_detection(data): |
优缺点:
-
✅ 简单直观,计算效率高
-
✅ 对正态分布数据效果良好
-
❌ 依赖正态分布假设
-
❌ 对偏态分布敏感
-
❌ 只能检测全局异常
适用场景:质量控制、金融收益率分析
1.2 Z-Score 方法
原理:计算数据点与均值的标准差距离
数学表达式:
1 | def z_score_detection(data, threshold=3): |
改进版本:
- 修正Z-Score:使用中位数和MAD(Median Absolute Deviation)
1
2
3
4
5def modified_z_score(data, threshold=3.5):
median = np.median(data)
mad = np.median(np.abs(data - median))
modified_z_scores = 0.6745 * (data - median) / mad # 0.6745为调整系数
return data[np.abs(modified_z_scores) > threshold]
1.3 箱线图法 (Boxplot)
原理:基于四分位数和IQR(Interquartile Range)识别异常值
实现:
1 | def boxplot_detection(data): |
阈值选择:
-
温和异常值:1.5×IQR
-
极端异常值:3×IQR
2. 基于距离的异常检测
2.1 K-最近邻 (K-Nearest Neighbors)
原理:计算每个点与其k个最近邻的距离,距离较大的点视为异常
实现:
python
from sklearn.neighbors import NearestNeighbors
def knn_outlier_detection(X, k=5, threshold=1.5):
neigh = NearestNeighbors(n_neighbors=k)
neigh.fit(X)
distances, indices = neigh.kneighbors(X)
# 计算平均距离
avg_distances = np.mean(distances, axis=1)
# 基于百分位数设置阈值
if threshold <= 1:
threshold_value = np.percentile(avg_distances, threshold * 100)
else:
threshold_value = np.mean(avg_distances) + threshold * np.std(avg_distances)
return avg_distances > threshold_value
优缺点:
-
✅ 无需分布假设
-
✅ 可发现任意形状的异常
-
❌ 计算复杂度高 O(n²)
-
❌ 对参数k敏感
-
❌ 高维数据效果差(维度灾难)
2.2 局部异常因子 (LOF - Local Outlier Factor)
原理:比较点的局部密度与其邻居的局部密度
实现:
1 | from sklearn.neighbors import LocalOutlierFactor |
核心概念:
-
k-距离:点到第k个最近邻的距离
-
可达距离:max(k-距离(p), 两点间距离)
-
局部可达密度:k个近邻的平均可达距离的倒数
-
LOF值:近邻的局部可达密度与当前点密度的比值
LOF值解释:
-
≈1:与邻居密度相似
-
<1:密度高于邻居(可能是内点)
-
1:密度低于邻居(可能是异常点)
3. 基于密度的异常检测
3.1 DBSCAN-based 异常检测
原理:基于密度的聚类,将不属于任何簇的点标记为异常
实现:
1 | from sklearn.cluster import DBSCAN |
参数选择:
eps:邻域半径min_samples:核心点所需的最小邻居数
3.2 局部异常概率 (LoOP - Local Outlier Probability)
原理:基于局部邻域的统计检验计算异常概率
特点:
- 提供0-1之间的异常概率
- 对局部密度变化更鲁棒
4. 基于树的异常检测
4.1 孤立森林 (Isolation Forest)
原理:异常点更容易被随机划分孤立
实现:
1 | from sklearn.ensemble import IsolationForest |
算法流程:
-
随机选择特征和分割值构建孤立树
-
计算每个点的路径长度(从根节点到该点的边数)
-
计算异常分数:
-
:路径长度的期望
-
:平均路径长度,用于标准化
-
异常分数解释:
-
接近1:很可能是异常
-
远小于0.5:很可能是正常点
-
所有点约0.5:没有明显异常
优缺点:
-
✅ 处理高维数据效果好
-
✅ 线性时间复杂度
-
✅ 无需距离或密度计算
-
❌ 对局部异常检测效果有限
5. 其他重要方法
5.1 一类支持向量机 (One-Class SVM)
原理:在特征空间中找到最优超平面,使大部分数据位于同一侧
1 | from sklearn.svm import OneClassSVM |
5.2 自编码器 (Autoencoder)
原理:基于重构误差检测异常
1 | from tensorflow.keras.models import Model |
6. 方法选择指南
| 方法 | 数据量 | 维度 | 异常类型 | 计算复杂度 | 是否需要标签 |
|---|---|---|---|---|---|
| 3σ/Z-Score | 小-大 | 低 | 全局 | O(n) | 否 |
| 箱线图 | 小-大 | 低 | 全局 | O(n log n) | 否 |
| KNN | 小-中 | 低-中 | 全局 | O(n²) | 否 |
| LOF | 小-中 | 低-中 | 局部 | O(n²) | 否 |
| 孤立森林 | 大 | 高 | 全局 | O(n log n) | 否 |
| One-Class SVM | 中 | 中-高 | 全局 | O(n²)-O(n³) | 否 |
| 自编码器 | 大 | 高 | 复杂模式 | O(epochs×n) | 否 |
7. 最佳实践建议
-
数据预处理:
-
处理缺失值和标准化
-
考虑数据分布特性
-
-
多方法结合:
1
2
3
4
5
6
7
8
9
10
11
12def ensemble_anomaly_detection(X, methods=['isolation_forest', 'lof']):
scores = []
if 'isolation_forest' in methods:
if_scores = IsolationForest().fit(X).score_samples(X)
scores.append(if_scores)
if 'lof' in methods:
lof_scores = LocalOutlierFactor().fit(X).negative_outlier_factor_
scores.append(lof_scores)
# 组合分数
combined_scores = np.mean(scores, axis=0)
return combined_scores -
阈值选择策略:
- 基于业务知识
- 基于历史数据分布
- 使用自适应阈值
-
验证与调优:
- 使用有标签数据验证(如有)
- 结合业务场景调整参数
- 定期重新训练模型