Scikit Learn - 异常检测
Scikit-Learn - 异常检测
Section titled “Scikit-Learn - 异常检测”本教程将探讨如何使用 Scikit-Learn 进行异常检测(anomaly detection),重点关注识别那些与数据集其余部分显著偏离的数据点。
异常检测是一种识别数据中不寻常模式或离群点(outliers)的关键技术。它在各种领域都有应用,例如欺诈检测(如不寻常的信用卡交易)、网络入侵检测、系统健康监控、医疗诊断(如识别扫描中的肿瘤)以及预测性维护。异常,也称为离群点,可以大致分为:
- 点异常(Point anomalies):相对于数据集的其余部分,单个数据实例是异常的。例如,单笔极高的购买金额。
- 情境异常(Contextual anomalies,或条件异常 Conditional anomalies):在特定情境下异常,但在其他情况下不异常的数据实例。例如,夏季取暖费过高就会被视为异常。
- 集体异常(Collective anomalies):一组相关的数据实例相对于整个数据集是异常的,即使这组数据中的单个实例并非异常。例如,人体心电图显示一段时期内出现异常平坦的线条,而这条线上的单个数据点在孤立来看可能正常。
异常检测方法
Section titled “异常检测方法”Scikit-Learn 主要支持两种主要的异常检测方法:
离群点检测 (Outlier Detection)
Section titled “离群点检测 (Outlier Detection)”在离群点检测中,训练数据被假定包含远离数据主体的离群点。离群点检测算法旨在对训练数据最集中的区域进行模型拟合,从而识别出偏离该规范的观测值。这通常被称为无监督异常检测(unsupervised anomaly detection),因为训练期间不使用表示正常或异常的标签。
新颖性检测 (Novelty Detection)
Section titled “新颖性检测 (Novelty Detection)”新颖性检测关注识别在训练数据中不存在的、新的或未见的观测模式。在这种场景下,训练数据被假定是“干净的”(未被离群点污染)。这通常被称为半监督异常检测(semi-supervised anomaly detection)。
Scikit-Learn 提供了一系列适用于离群点和新颖性检测的机器学习工具。这些工具,像其他 Scikit-Learn 估计器(estimators)一样,使用 fit() 方法从数据中学习:
estimator.fit(X_train)训练完成后,可以使用 predict() 方法将新的观测值分类为正常点(inliers,通常标记为 1 或 True)或离群点/新颖点(outliers/novelties,通常标记为 -1 或 False):
predictions = estimator.predict(X_test)许多估计器还提供了 score_samples() 方法,该方法返回每个样本的原始得分(得分越高,越正常)。predict() 方法通常对这些原始得分应用一个阈值。这个阈值有时可以通过 contamination 参数控制,它代表数据集中预期的离群点比例。
或者,对于某些估计器,可以使用 decision_function() 方法。它通常为正常点返回正值,为离群点返回负值。
decision_scores = estimator.decision_function(X_test)Scikit-Learn 用于异常检测的算法
Section titled “Scikit-Learn 用于异常检测的算法”让我们探索 Scikit-Learn 中一些流行的异常检测算法。
椭圆包络 (Elliptic Envelope) (covariance.EllipticEnvelope)
Section titled “椭圆包络 (Elliptic Envelope) (covariance.EllipticEnvelope)”Elliptic Envelope 算法假设正常数据来自已知分布,通常是高斯分布。它对数据进行稳健的协方差估计,有效地将一个椭圆拟合到中心数据点,同时将椭圆外部的点识别为离群点。此方法最适合于正态分布的数据。
sklearn.covariance.EllipticEnvelope 的常用参数:
| 参数 (Parameter) | 描述 (Description) |
|---|---|
| store_precision | 布尔值,默认为 True。如果为 True,则存储估计的精度矩阵。该属性为 precision_。 |
| assume_centered | 布尔值,默认为 False。如果为 False,则使用 FastMCD 算法计算稳健的位置和协方差。如果为 True,则假定数据已中心化,FastMCD 算法从这些中心化数据计算稳健位置和协方差的支持集。设置为 True 在数据已中心化时有用,可以加快计算速度。 |
| support_fraction | 介于 (0., 1.] 之间的浮点数,默认为 None。用于原始 MCD 估计支持集的点比例。如果为 None,则设置为 (n_samples + n_features + 1) / 2 / n_samples。必须大于 contamination。 |
| contamination | 介于 (0., 0.5) 之间的浮点数,默认为 0.1。数据集中预期的离群点比例。这定义了马氏距离(Mahalanobis distances)的阈值,用于将点标记为离群点。 |
| random_state | 整型、RandomState 实例或 None,默认为 None。控制稳健协方差估计的伪随机性。传入一个整型可以确保多次函数调用输出可复现。 |
拟合 EllipticEnvelope 后重要的属性:
| 属性 (Attribute) | 描述 (Description) |
|---|---|
| location_ | 类数组(array-like),形状为 (n_features,)。估计的稳健位置(均值)。 |
| covariance_ | 类数组(array-like),形状为 (n_features, n_features)。估计的稳健协方差矩阵。 |
| precision_ | 类数组(array-like),形状为 (n_features, n_features)。估计的协方差矩阵伪逆(精度矩阵)。 |
| support_ | 类数组(array-like),形状为 (n_samples,)。用于计算稳健位置和形状估计的观测值掩码。 |
| offset_ | 浮点数。用于根据原始得分定义决策函数的偏移量。decision_function = score_samples - offset_。 |
实现示例:
import numpy as npfrom sklearn.covariance import EllipticEnvelope# Generate some data (for example purposes)# 生成一些数据(仅为示例)# True covariance matrix of the inliers# 正常点的真实协方差矩阵true_cov = np.array([[0.8, 0.3], [0.3, 0.4]])X_inliers = np.random.RandomState(0).multivariate_normal(mean=[0, 0], cov=true_cov, size=200)# Add some outliers# 添加一些离群点X_outliers = np.random.RandomState(1).multivariate_normal(mean=[5, 5], cov=[[1,0],[0,1]], size=20)X = np.vstack([X_inliers, X_outliers])
# Fit the Elliptic Envelope model# 拟合 Elliptic Envelope 模型cov_model = EllipticEnvelope(random_state=0, contamination=0.1) # contamination approx 20/220cov_model.fit(X)
# Predict outliers (1 for inlier, -1 for outlier)# 预测离群点 (1 表示正常点, -1 表示离群点)# For example, test points [0,0] (expected inlier) and [6,6] (expected outlier)# 例如,测试点 [0,0] (预期正常点) 和 [6,6] (预期离群点)predictions = cov_model.predict([[0, 0], [6, 6]])print(f"Predictions: {predictions}")# Mahalanobis distances (raw scores)# 马氏距离 (原始得分)mahal_dist = cov_model.mahalanobis(X)# print(f"First 5 Mahalanobis distances: {mahal_dist[:5]}")# print(f"前 5 个马氏距离: {mahal_dist[:5]}")预期输出(由于数据生成中的随机性,如果未完全固定随机种子,输出可能略有差异):
Predictions: [ 1 -1]实用提示:当正常点集中且近似服从高斯分布时,Elliptic Envelope 效果良好。对于多模态数据,它可能表现不佳。
隔离森林 (Isolation Forest) (ensemble.IsolationForest)
Section titled “隔离森林 (Isolation Forest) (ensemble.IsolationForest)”隔离森林是一种高效的离群点检测算法,特别适用于高维数据集。它通过随机划分数据来隔离观测值。其核心思想是,离群点是“少数且不同的”,因此比正常点更容易被隔离。隔离一个样本所需的分割次数等同于树结构中从根节点到终止节点的路径长度。
sklearn.ensemble.IsolationForest 的常用参数:
| 参数 (Parameter) | 描述 (Description) |
|---|---|
| n_estimators | 整型,默认为 100。集成模型中基础估计器(树)的数量。 |
| max_samples | 整型或浮点型,默认为 ‘auto’。从 X 中抽取的样本数量,用于训练每个基础估计器。如果为 ‘auto’,则设置为 max_samples=min(256, n_samples)。 |
| contamination | 浮点型或 ‘auto’,默认为 ‘auto’。数据集中离群点的比例。如果为 ‘auto’,阈值按照原始论文确定,对于 novelty=False 对应 0.1。对于 novelty=True,默认为 0.0。设置为浮点数时,应在范围 (0, 0.5] 内。 |
| max_features | 整型或浮点型,默认为 1.0。从 X 中抽取的特征数量,用于训练每个基础估计器。 |
| bootstrap | 布尔值,默认为 False。如果为 True,则个体树在有放回抽样的训练数据随机子集上拟合。如果为 False,则进行无放回抽样。 |
| random_state | 整型、RandomState 实例或 None,默认为 None。控制特征选择和分裂点选择的伪随机性。 |
| n_jobs | 整型,默认为 None。用于 fit 和 predict 并行运行的作业数。None 表示 1,除非在 joblib.parallel_backend 上下文中使用。-1 表示使用所有处理器。 |
| warm_start | 布尔值,默认为 False。如果设置为 True,则复用上次调用 fit 的结果,并向集成模型添加更多估计器;否则,重新拟合一个全新的森林。 |
拟合 IsolationForest 后重要的属性:
| 属性 (Attribute) | 描述 (Description) |
|---|---|
| estimators_ | DecisionTreeClassifier 列表。拟合好的子估计器集合。 |
| max_samples_ | 整型。max_samples 实际使用的样本数量。 |
| offset_ | 浮点数。用于根据原始得分定义决策函数的偏移量。decision_function = score_samples - offset_。 |
实现示例:
from sklearn.ensemble import IsolationForestimport numpy as np
# Generate some data# 生成一些数据rng = np.random.RandomState(42)X_inliers = 0.3 * rng.randn(100, 2)X_inliers = np.r_[X_inliers + 2, X_inliers - 2] # Two clusters# 两个聚类X_outliers = rng.uniform(low=-4, high=4, size=(20, 2))X = np.r_[X_inliers, X_outliers]
# Fit the Isolation Forest model# 拟合隔离森林模型# For newer scikit-learn versions, contamination='auto' behaves like 0.1# 对于较新版本的 scikit-learn, contamination='auto' 的行为类似于 0.1# For explicit control, set contamination to a float e.g. 0.1 for 10% outliers# 为了精确控制,可以将 contamination 设置为浮点数,例如 0.1 表示 10% 离群点iso_forest = IsolationForest(n_estimators=100, contamination='auto', random_state=42)iso_forest.fit(X)
# Predict outliers# 预测离群点y_pred = iso_forest.predict(X) # -1 for outliers, 1 for inliers# -1 表示离群点, 1 表示正常点
# Example: check one known inlier and one known outlier point from generation# 示例: 检查一个已知正常点和一个已知离群点 (来自数据生成时)# (adjust indices based on your data generation if different)# (如果你的数据生成方式不同,请调整索引)print(f"Prediction for a typical inlier-like point [2,2]: {iso_forest.predict([[2,2]])}")print(f"Prediction for a typical outlier-like point [-3,-3]: {iso_forest.predict([[-3,-3]])}")
# To get anomaly scores:# 获取异常得分:# scores = iso_forest.decision_function(X)# print(f"Decision scores for first 5 points: {scores[:5]}")# print(f"前 5 个点的决策得分: {scores[:5]}")示例输出(具体的模型参数可能在输出中有所不同):
Prediction for a typical inlier-like point [2,2]: [1]Prediction for a typical outlier-like point [-3,-3]: [-1]实用提示:隔离森林通常很稳健且可扩展性好。contamination 参数是调整其敏感度的关键。
局部离群因子 (Local Outlier Factor, LOF) (neighbors.LocalOutlierFactor)
Section titled “局部离群因子 (Local Outlier Factor, LOF) (neighbors.LocalOutlierFactor)”局部离群因子 (LOF) 是一种无监督算法,用于计算反映观测值异常程度的得分。它衡量给定数据点相对于其邻居的局部密度偏差。密度显著低于其邻居的点被认为是离群点。
sklearn.neighbors.LocalOutlierFactor 的常用参数:
| 参数 (Parameter) | 描述 (Description) |
|---|---|
| n_neighbors | 整型,默认为 20。默认用于 k 近邻查询的邻居数量。 |
| algorithm | {‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’},默认为 ‘auto’。用于计算最近邻的算法。 |
| leaf_size | 整型,默认为 30。传递给 BallTree 或 KDTree 的叶子大小。可能影响构建和查询的速度以及存储树所需的内存。 |
| metric | 字符串或可调用对象,默认为 ‘minkowski’。用于距离计算的度量标准。默认为 ‘minkowski’,当 p=2 时,结果是标准的欧氏距离(Euclidean distance)。 |
| p | 整型,默认为 2。Minkowski 度量标准的参数。当 p=1 时,等同于使用 manhattan_distance (l1),当 p=2 时等同于 euclidean_distance (l2)。 |
| contamination | 浮点型或 ‘auto’,默认为 ‘auto’。数据集中离群点的比例。当为 ‘auto’ 时,设置为 0.1。范围是 (0, 0.5]。在 novelty=False 时使用。 |
| novelty | 布尔值,默认为 False。如果为 True,LocalOutlierFactor 用于新颖性检测(在干净数据上训练,在新的未知数据上预测)。如果为 False,则用于离群点检测(识别训练数据中的离群点)。 |
| n_jobs | 整型,默认为 None。用于邻居搜索并行运行的作业数。None 表示 1,除非在 joblib.parallel_backend 上下文中使用。-1 表示使用所有处理器。 |
拟合 LocalOutlierFactor 后重要的属性:
| 属性 (Attribute) | 描述 (Description) |
|---|---|
| negative_outlier_factor_ | numpy 数组,形状为 (n_samples,)。训练样本的局部离群因子(Local Outlier Factor)的相反数。值越高,越正常。正常点的 LOF 得分接近 1,而离群点则具有显著更大的 LOF。Scikit-learn 存储这些值的相反数,因此正常点的值将接近 -1。 |
| n_neighbors_ | 整型。用于 k 近邻查询的实际邻居数量。 |
| offset_ | 浮点数。用于根据原始得分定义二元标签的偏移量。decision_function = score_samples - offset_。 |
实现示例(离群点检测):
import numpy as npfrom sklearn.neighbors import LocalOutlierFactor
# Generate sample data: a cluster of normal points and a few outliers# 生成样本数据:一个正常点聚类和少数离群点np.random.seed(42)X_inliers = 0.5 * np.random.randn(100, 2) + [2, 2]X_outliers = np.random.uniform(low=-4, high=8, size=(20, 2))X = np.vstack([X_inliers, X_outliers])
# Initialize and fit LOF model for outlier detection# 初始化并拟合用于离群点检测的 LOF 模型# contamination='auto' implies 0.1. Adjust as needed.# contamination='auto' 表示 0.1。根据需要调整。lof = LocalOutlierFactor(n_neighbors=20, contamination='auto')
# For outlier detection, use fit_predict()# 对于离群点检测,使用 fit_predict()# It fits the model and then predicts labels (-1 for outliers, 1 for inliers)# 它拟合模型然后预测标签 (-1 表示离群点, 1 表示正常点)y_pred = lof.fit_predict(X)
# Example: Print predictions for the first 5 points and last 5 points# 示例:打印前 5 个点和后 5 个点的预测结果# (assuming outliers were appended last in X)# (假设离群点被附加在 X 的最后)print(f"Predictions for first 5 (likely inliers): {y_pred[:5]}")print(f"Predictions for last 5 (likely outliers): {y_pred[-5:]}")
# Access the negative outlier factor scores# 访问负局部离群因子得分# Scores close to -1 are more normal; more negative scores (e.g., -2, -5) are more outlying.# 分数接近 -1 更正常;分数越负(例如 -2, -5),越可能是离群点。# X_scores = lof.negative_outlier_factor_# print(f"Negative outlier factor for first 5 points: {X_scores[:5]}")# print(f"前 5 个点的负局部离群因子: {X_scores[:5]}")# print(f"Negative outlier factor for last 5 points: {X_scores[-5:]}")# print(f"后 5 个点的负局部离群因子: {X_scores[-5:]}")预期输出(标签可能因具体数据生成和参数设置略有差异):
Predictions for first 5 (likely inliers): [1 1 1 1 1]Predictions for last 5 (likely outliers): [-1 -1 -1 -1 -1]实用提示:LOF 擅长发现低密度区域的离群点。n_neighbors 的选择是关键。如果 novelty=True,它可用于新颖性检测,此时在干净数据上调用 fit,在新数据上调用 predict。
单类别支持向量机 (One-Class SVM) (svm.OneClassSVM)
Section titled “单类别支持向量机 (One-Class SVM) (svm.OneClassSVM)”单类别支持向量机(One-Class Support Vector Machine)是一种无监督算法,它学习一个决策边界,将高数据密度区域与稀疏区域分开。它在高维空间中有效,并且可以捕获数据分布的复杂形状。它需要在干净数据上进行训练(新颖性检测设置),或者如果用于离群点检测,它将尝试围绕数据主体找到边界。
它学习一个决策函数用于新颖性检测:它将新数据分类为与训练集相似或不同。关键参数包括 kernel(例如 ‘rbf’, ‘linear’)和 nu。nu 参数(训练误差的上限以及支持向量比例的下限)控制着找到紧密边界和包含所有训练点之间的权衡。
sklearn.svm.OneClassSVM 的常用参数:
| 参数 (Parameter) | 描述 (Description) |
|---|---|
| kernel | 字符串,默认为 ‘rbf’。指定算法中使用的核类型(‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’)。 |
| degree | 整型,默认为 3。多项式核函数(‘poly’)的次数。被所有其他核忽略。 |
| gamma | {‘scale’, ‘auto’} 或浮点型,默认为 ‘scale’。‘rbf’, ‘poly’ 和 ‘sigmoid’ 的核系数。如果传入 gamma='scale'(默认),则使用 1 / (n_features * X.var()) 作为 gamma 的值。 |
| nu | 浮点型,默认为 0.5。训练误差比例的上限和支持向量比例的下限。应在区间 (0, 1] 内。 |
| tol | 浮点型,默认为 1e-3。停止准则的容忍度。 |
| shrinking | 布尔值,默认为 True。是否使用缩减启发式算法。 |
实现示例:
import numpy as npfrom sklearn.svm import OneClassSVM
# Generate some data - mostly clustered, with a few points further away# 生成一些数据 - 大部分聚类在一起,少数点离得较远rng = np.random.RandomState(42)X_train = 0.3 * rng.randn(100, 2)X_train = np.r_[X_train + 2, X_train - 2] # Two clusters# 两个聚类X_test_normal = [[2.1, 2.1], [-1.9, -1.9]] # Points similar to training data# 与训练数据相似的点X_test_outliers = [[0,0], [5,5]] # Points different from training data# 与训练数据不同的点
# Fit the One-Class SVM model# 拟合单类别 SVM 模型# nu=0.1 means we expect about 10% of training data to be outliers/on the wrong side of boundary# nu=0.1 意味着我们预计约 10% 的训练数据是离群点/位于边界的错误一侧# Or, it controls the number of support vectors.# 或者,它控制支持向量的数量。one_class_svm = OneClassSVM(kernel='rbf', gamma='scale', nu=0.1)one_class_svm.fit(X_train)
# Predict on new data# 在新数据上进行预测pred_normal = one_class_svm.predict(X_test_normal)pred_outliers = one_class_svm.predict(X_test_outliers)
print(f"Predictions for normal-like test points: {pred_normal}")print(f"Predictions for outlier-like test points: {pred_outliers}")
# Get raw scores (signed distance to the separating hyperplane)# 获取原始得分 (到分离超平面的有符号距离)# scores_normal = one_class_svm.score_samples(X_test_normal)# print(f"Scores for normal-like test points: {scores_normal}")# print(f"正常点测试样本的得分: {scores_normal}")预期输出:
Predictions for normal-like test points: [ 1 1]Predictions for outlier-like test points: [-1 -1]有关每种算法的更详细信息和更多示例,请参阅官方 Scikit-Learn 异常点检测文档。
选择正确的异常检测算法及其参数通常取决于您数据的特性以及您的情境中对“异常”的具体定义。实验和领域知识是关键。