2.7. 新奇和异常检测#

许多应用需要能够判断一个新观测值是否属于与现有观测值相同的分布(它是*内点*),或者应该被视为不同(它是*异常点*)。通常,这种能力用于清理真实数据集。必须做出两个重要的区分:

异常检测:

训练数据包含异常点,这些异常点被定义为远离其他观测值的观测值。因此,异常检测估计器试图拟合训练数据最密集的区域,忽略异常的观测值。

新奇检测:

训练数据未被异常点污染,我们感兴趣的是检测一个**新**观测值是否是异常点。在这种情况下,异常点也称为新奇点。

异常检测和新奇检测都用于异常检测,其中一个感兴趣的是检测异常或不寻常的观测值。异常检测也称为无监督异常检测,而新奇检测称为半监督异常检测。在异常检测的背景下,异常点/异常值不能形成密集的簇,因为可用的估计器假设异常点/异常值位于低密度区域。相反,在新奇检测的背景下,新奇点/异常值可以形成密集的簇,只要它们位于训练数据的低密度区域,在这个背景下被视为正常。

scikit-learn项目提供了一组机器学习工具,可以用于新奇或异常检测。这种策略通过从数据中无监督地学习对象来实现:

estimator.fit(X_train)

然后可以使用 predict 方法将新观测值分类为内点或异常点:

estimator.predict(X_test)

内点被标记为1,而离群点被标记为-1。 predict 方法利用了估计器计算的原始评分函数上的阈值。这个评分函数可以通过 score_samples 方法访问,而阈值可以通过 contamination 参数控制。

decision_function 方法也是从评分函数定义的,使得负值为离群点,非负值为内点:

estimator.decision_function(X_test)

注意,neighbors.LocalOutlierFactor 默认不支持 predictdecision_functionscore_samples 方法,而只支持一个 fit_predict 方法,因为这个估计器最初是为了离群点检测而设计的。训练样本的异常分数可以通过 negative_outlier_factor_ 属性访问。

如果你确实想将:class:neighbors.LocalOutlierFactor 用于新颖性检测,即预测标签或计算新未见数据的异常分数,你可以在拟合估计器之前,将估计器实例化时将 novelty 参数设置为 True 。在这种情况下, fit_predict 方法不可用。

Warning

使用局部离群因子进行新颖性检测

novelty 设置为 True 时,请注意你只能在新未见数据上使用 predictdecision_functionscore_samples 方法,而不能在训练样本上使用,因为这会导致错误的结果。也就是说, predict 的结果将与 fit_predict 不同。训练样本的异常分数始终可以通过 negative_outlier_factor_ 属性访问。

neighbors.LocalOutlierFactor 的行为总结在下表中。

fit_predict 正常 不可用 predict 不可用 仅在新数据上使用 decision_function 不可用 仅在新数据上使用 score_samples 使用 negative_outlier_factor_ 仅在新数据上使用 negative_outlier_factor_ 正常 正常

scikit-learn 中异常检测算法的比较。局部异常因子(LOF)没有显示黑色的决策边界,因为它在用于异常检测时,没有可以在新数据上应用的预测方法。

../_images/sphx_glr_plot_anomaly_comparison_001.png

ensemble.IsolationForestneighbors.LocalOutlierFactor 在考虑的数据集上表现良好。 svm.OneClassSVM 以其对异常值的敏感性而闻名,因此在异常检测方面表现不佳。尽管如此,在高维度或没有任何关于内联数据分布假设的情况下进行异常检测是非常具有挑战性的。svm.OneClassSVM 仍然可以用于异常检测,但需要对其超参数 nu 进行精细调整,以处理异常值并防止过拟合。 linear_model.SGDOneClassSVM 提供了一个线性复杂度的线性单类 SVM 实现。这个实现在这里与核近似技术一起使用,以获得与默认使用高斯核的 svm.OneClassSVM 类似的结果。最后,covariance.EllipticEnvelope 假设数据是 高斯分布并学习一个椭圆。有关不同估计器的更多详细信息,请参阅示例 比较用于异常检测的算法在玩具数据集上的表现 和以下各节。

示例

2.7.1. 新颖性检测#

考虑一个由 \(p\) 个特征描述的相同分布的 \(n\) 个观测数据集。现在,我们向该数据集添加一个观测值。这个新观测值与其他的如此不同,以至于我们怀疑它是正常的吗?(即,它是否来自相同的分布?)或者相反,它与其他观测值如此相似,以至于我们无法将其与原始观测值区分开来?这就是新颖性检测工具和方法所解决的问题。

一般来说,这是为了学习一个粗糙的、接近的边界,该边界限定初始观测分布的轮廓,在嵌入的 \(p\) 维空间中绘制。然后,如果进一步的观测值位于边界限定的子空间内,则认为它们来自与初始观测值相同的群体。否则,如果它们位于边界之外,我们可以说它们在给定的评估置信度下是异常的。

One-Class SVM 由 Schölkopf 等人引入,用于此目的,并在 支持向量机 模块中的 svm.OneClassSVM 对象中实现。它需要选择一个 内核和一个标量参数来定义一个边界。通常选择RBF内核,尽管不存在设置其带宽参数的精确公式或算法。这是scikit-learn实现中的默认设置。 nu 参数,也称为One-Class SVM的边际,对应于在边界外发现新但正常的观测值的概率。

参考文献

示例

../_images/sphx_glr_plot_oneclass_001.png

2.7.1.1. 扩展One-Class SVM#

One-Class SVM的在线线性版本在 linear_model.SGDOneClassSVM 中实现。此实现与样本数量线性扩展,并且可以使用核近似来近似核化 svm.OneClassSVM 的解,其复杂度在最优情况下是样本数量的二次方。更多细节请参见 在线一类 SVM 部分。

示例

2.7.2. 异常检测#

异常检测类似于新颖性检测,其目标是将核心的正常观测值与一些称为*异常值*的污染观测值分开。然而,在异常检测的情况下,我们不假设有干净的训练数据集。 检测,我们没有一个干净的数据集代表常规观测的总体,可以用来训练任何工具。

2.7.2.1. 拟合椭圆信封#

执行异常值检测的一种常见方法是假设常规数据来自已知分布(例如,数据呈高斯分布)。基于这一假设,我们通常尝试定义数据的“形状”,并将远离拟合形状的观测定义为异常观测。

scikit-learn 提供了一个对象 covariance.EllipticEnvelope ,它对数据进行稳健的协方差估计,从而将椭圆拟合到中心数据点,忽略中心模式外的点。

例如,假设内部数据呈高斯分布,它将以稳健的方式估计内部数据的位置和协方差(即,不受异常值的影响)。从该估计中获得的马氏距离用于推导出异常程度的度量。这种策略如下所示。

../_images/sphx_glr_plot_mahalanobis_distances_001.png

示例

参考文献

  • Rousseeuw, P.J., Van Driessen, K. “A fast algorithm for the minimum covariance determinant estimator” Technometrics 41(3), 212 (1999)

2.7.2.2. 孤立森林#

在高维数据集中执行异常值检测的一种有效方法是使用随机森林。 ensemble.IsolationForest 通过随机选择一个特征,然后在该特征的最大值和最小值之间随机选择一个分割值,来“隔离”观测值。

由于递归分区可以表示为一个树结构,因此隔离一个样本所需的分割次数相当于从根节点到终止节点的路径长度。

这个路径长度,在这样随机树的森林上进行平均,是衡量正常性的指标,也是我们的决策函数。

随机分区明显产生较短的路径用于异常值。因此,当随机树的森林共同为特定样本产生较短的路径长度时,它们极有可能是异常值。

ensemble.IsolationForest 的实现基于 tree.ExtraTreeRegressor 的集成。根据 Isolation Forest 原始论文,每棵树的最大深度设置为 \(\lceil \log_2(n) \rceil\) ,其中 \(n\) 是用于构建树的样本数量(更多细节请参见 (Liu et al., 2008))。

该算法如下所示。

../_images/sphx_glr_plot_isolation_forest_003.png

ensemble.IsolationForest 支持 warm_start=True ,这允许您向已经拟合的模型添加更多树:

>>> from sklearn.ensemble import IsolationForest
>>> import numpy as np
>>> X = np.array([[-1, -1], [-2, -1], [-3, -2], [0, 0], [-20, 50], [3, 5]])
>>> clf = IsolationForest(n_estimators=10, warm_start=True)
>>> clf.fit(X)  # 拟合10棵树  
>>> clf.set_params(n_estimators=20)  # 增加10棵树  
>>> clf.fit(X)  # 拟合增加的树  

示例

参考文献

  • Liu, Fei Tony, Ting, Kai Ming 和 Zhou, Zhi-Hua. “Isolation forest.” 数据挖掘, 2008. ICDM’08. 第八届IEEE国际会议.

2.7.2.3. 局部异常因子#

另一种在适度高维数据集上执行异常检测的有效方法是使用局部异常因子(LOF)算法。

neighbors.LocalOutlierFactor (LOF)算法计算一个分数(称为局部异常因子), 反映观测值的异常程度。它测量给定数据点相对于其邻居的局部密度偏差。 其思想是检测那些相对于其邻居密度显著较低的样本。

实际上,局部密度是通过k近邻获得的。一个观测值的LOF分数等于其k近邻的平均局部密度与其自身局部密度的比值: 正常实例的局部密度预计与其邻居相似,而异常数据预计具有小得多的局部密度。

考虑的邻居数量k(别名参数n_neighbors)通常选择为1)大于一个簇必须包含的最小对象数, 以便其他对象可以相对于该簇成为局部异常值,以及2)小于可能成为局部异常值的最近对象的最大数量。 实际上,这种信息通常不可用,通常n_neighbors=20在一般情况下表现良好。 当异常值的比例较高时(例如,超过10%,如下例所示),n_neighbors 应该更大(在下例中为 n_neighbors=35)。

LOF 算法的优势在于它同时考虑了数据集的局部和全局属性:即使在异常样本具有不同基础密度的数据集中,它也能表现良好。关键不在于样本有多孤立,而在于它相对于周围邻域有多孤立。

在应用 LOF 进行异常检测时,没有 predictdecision_functionscore_samples 方法,只有 fit_predict 方法。训练样本的异常得分可以通过 negative_outlier_factor_ 属性访问。请注意,当 LOF 用于新奇检测(即 novelty 参数设置为 True 时),可以在新的未见数据上使用 predictdecision_functionscore_samples ,但 predict 的结果可能与 fit_predict 不同。参见 使用 Local Outlier Factor 进行新奇检测

以下是该策略的图示。

../_images/sphx_glr_plot_lof_outlier_detection_001.png

示例

参考文献

2.7.3. 使用 Local Outlier Factor 进行新奇检测#

要使用 neighbors.LocalOutlierFactor 进行新奇检测,即… 预测新未见数据的标签或计算异常分数,您需要在拟合估计器之前,将估计器的 novelty 参数设置为 True 来实例化估计器:

lof = LocalOutlierFactor(novelty=True)
lof.fit(X_train)

请注意,在这种情况下 fit_predict 是不可用的,以避免不一致性。

Warning

使用局部异常因子进行新奇检测

novelty 设置为 True 时,请注意您只能在新未见数据上使用 predictdecision_functionscore_samples ,而不能在训练样本上使用,因为这会导致错误的结果。也就是说, predict 的结果将与 fit_predict 不同。训练样本的异常分数始终可以通过 negative_outlier_factor_ 属性访问。

下面展示了使用局部异常因子进行新奇检测的示例。

../_images/sphx_glr_plot_lof_novelty_detection_001.png