Skip to content

2.7. 新奇点与离群点检测(Novelty and Outlier Detection)

许多应用程序要求能够决定一个新的观测值是属于与现有观测值相同的分布(它是一个内联值),还是应该被视为不同的分布(它是一个离群值)。通常,此功能用于清理实际数据集。必须作出两个重要区分:

  • 异常点检测

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

  • 新奇点检测

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

离群点检测和新奇点检测都用于异常点检测,异常点检测针对对异常或不寻常的观察结果。离群点检测也称为无监督异常检测,新奇点检测称为半监督异常检测。在离群点检测中,由于可用的估计器假设离群点/异常点位于低密度区域,因此,离群点/异常点不能形成密集的聚类。相反,在新奇点检测的情况下,只要新奇点/异常点位于训练数据的低密度区域(在这种情况下被认为是正常的),它们就可以形成密集的簇。

scikit-learn项目提供了一套机器学习工具,可用于新奇点或离群点检测。通过从数据中以无监督的方式学习对象来实现此策略。

estimator.fit(X_train)

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

estimator.predict(X_test)

内联项标记为1,而异常值标记为-1。该预测方法在估计器计算的原始评分函数(raw scoring function)上使用了一个阈值(threshold )。此评分函数可通过 score_samples方法进行访问,而阈值可由contamination 参数来控制。

decision_function方法也是从评分函数定义的,这样负的值是异常值,非负的值是内联值:

estimator.decision_function(X_test)

请注意,neighbors.LocalOutlierFactor默认不支持predict, decision_functionscore_samples 方法,而仅支持 fit_predict 方法,因为此估计器最初是用于离群点检测的。训练样本的异常得分可以通过 negative_outlier_factor_ 属性获得。

如果您真的想使用neighbors.LocalOutlierFactor进行新奇点检测,即预测标签或计算新的未见过的数据的异常得分,则可以在拟合估计器之前将 novelty参数设置为True来实例化估计器。在这种情况下,fit_predict方法不可用。

警告: 使用局部离群因子进行新奇点检测

novelty设置为 True 时,请注意,您必须只对新的未见过数据而不是对训练样本使用 predict, decision_functionscore_samples 方法,因为这将导致错误的结果。训练样本的异常得分可以通过 negative_outlier_factor_ 属性获得。

下表总结了neighbors.LocalOutlierFactor类用于离群点和新奇点检测的行为。

方法 离群点检测 Novelty detection
fit_predict OK 不可用
predict 不可用 仅用于新数据
decision_function 不可用 仅用于新数据
score_samples 使用 negative_outlier_factor_ 仅用于新数据

2.7.1. 离群点检测方法综述

scikit-learn中离群点检测算法的比较如下图所示。局部离群因子(Local Outlier Factor,简称 LOF)在用于离群点检测时,由于没有可应用于新数据的预测方法,因此不会以黑色线条显示决策边界。

https://scikit-learn.org/stable/_images/sphx_glr_plot_anomaly_comparison_0011.png

ensemble.IsolationForestneighbors.LocalOutlierFactor在这里考虑的数据集上表现相当好。众所周知,svm.OneClassSVM 对离群点非常敏感,因此在离群点检测方面表现不太好。最后,covariance.EllipticEnvelope假设数据是呈高斯分布的,并学习一个椭圆。有关不同估计器的更多详细信息,请参阅比较在toy数据集上进行离群点检测算法的示例和以下各小节。

示例:

2.7.2. 新奇点检测(Novelty Detection)

考虑由$p$特征描述的服从同一分布的$n$个观测数据集。现在我们再给这个数据集添加一个观察值。新的观察结果与其他观察结果有如此大的不同,以至于我们怀疑它是否正常?(即是否来自同一个分布?)或者恰恰相反,它与另一个非常相似,以至于我们无法将其与原始观测区分开来?这是新奇点检测工具和方法所要解决的问题。

一般来说,它将学习一个划定初始观测值分布轮廓的粗糙,紧密边界,并绘制在嵌入p维空间中。然后,如果进一步的观测位于边界限定的子空间内,则认为它们来自与初始观测相同的总体。否则,如果他们在边界之外,根据给定的评估中的置信度,我们可以说他们是不正常的。

Schölkopf 等人引入了一类支持向量机(One-Class SVM),并在svm.OneClassSVM对象的Support Vector Machines 模块中实现。它需要选择一个内核和一个标量参数来定义边界。虽然没有精确的公式和算法来设置RBF核的带宽(bandwidth)参数,但通常选择RBF核。这是scikit-learn实现中的默认设置。$ν$参数,也称为一类支持向量机(One-Class SVM)的边缘,对应于在边界之外找到新的但有规律的观测值的概率。

示例:

https://scikit-learn.org/stable/_images/sphx_glr_plot_oneclass_0011.png

2.7.3. 离群点检测(Outlier Detection)

离群点检测与新奇点检测类似,其目的是将常规观测点的核心与污染观测点(称为离群点(outliers))的核心分离。然而,在离群点检测的情况下,我们没有一个干净的数据集来表示可用于训练任何工具的常规观测的总体。

2.7.3.1. 拟合椭圆模型(Fitting an elliptic envelope)

执行离群点检测的一种常见方法是假设规则数据来自已知分布(例如,数据呈高斯分布)。从这个假设出发,我们通常试图定义数据的“形状”,并且可以将外围观测值(outlying observations)定义为离拟合形状足够远的观测值。

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

例如,假设内部数据是呈高斯分布的,它将以稳健的方式(即不受离群值影响)估计内部位置和协方差。从这个估计中得到的马氏距离(Mahalanobis distances)用得出离群度(outlyingness)度量。这一策略如下所示。

https://scikit-learn.org/stable/_images/sphx_glr_plot_mahalanobis_distances_0011.png

示例::

参考文献:

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

2.7.3.2. 孤立森林(Isolation Forest)

在高维数据集中进行离群点检测的一种有效方法是使用随机森林(random forests)。ensemble.IsolationForest通过随机选择一个特征,然后在所选特征的最大值和最小值之间随机选择一个分割值来“隔离”观察结果。

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

在这样一个随机树组成的森林中的平均路径长度,是一个正态性和我们的决策函数的度量。

随机分割产生的异常路径明显更短。因此,当由随机树组成的森林为特定样本共同产生较短的路径长度时,它们很可能是异常的。

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

该算法如下所示。

https://scikit-learn.org/stable/_images/sphx_glr_plot_isolation_forest_0011.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 and Zhou, Zhi-Hua. “Isolation forest.” Data Mining, 2008. ICDM’08. Eighth IEEE International Conference on.

2.7.3.3. 局部离群因子(Local Outlier Factor)

另一种对中等高维数据集进行离群点检测的有效方法是使用局部离群点因子(Local Outlier Factor (LOF))算法。

neighbors.LocalOutlierFactor (LOF) 算法计算了一个反映观测值异常程度的分数(称为局部异常因子)。它测量给定数据点相对于其邻域的局部密度偏差。这样做的目的是检测出密度比它们的邻居低得多的样本。

实际上,局部密度是从k近邻(k-nearest)得到的。观测值的LOF得分等于k近邻的平均局部密度与其自身的局部密度之比:一个正常实例的局部密度与相邻实例的相似,而异常数据的局部密度则要小得多。

所考虑的邻居数 k(别名参数n_neighbors)通常被选择为 1)大于一个集群(cluster)必须包含的最小对象数,以便其他对象可以是相对于该集群(cluster)的局部离群点,且 2)小于可能是局部离群点的最大近邻对象数。在实践中,这些信息通常是不可用的,通常,设n_neighbors=20似乎效果很好。当离群点的比例较高时(如以下示例中大于10%),n_neighbors 应更大(以下示例中n_neighbors =35)。

LOF算法的优点在于,它同时考虑了数据集的局部和全局特性:即使在异常样本具有不同密度的数据集中,LOF算法也能取得良好的性能。问题不在于样本有多孤立,而在于它相对于周围邻居的孤立程度。

在应用LOF进行离群点检测时,没有 predict, decision_functionscore_samples 方法,只有fit_predict方法。训练样本的异常得分可通过negative_outlier_factor_ 属性获得。注意,当LOF用于新奇点检测时,即当 novelty 参数设置为True时,可以对新的未见过的数据使用predict, decision_functionscore_samples方法。参见使用局部离群因子的新奇点检测

这一策略如下所示。

https://scikit-learn.org/stable/_images/sphx_glr_plot_lof_outlier_detection_0011.png

示例:

参考文献:

2.7.4. 使用局部离群因子的新奇点检测(Novelty detection with Local Outlier Factor)

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

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

注意,fit_predict在这种情况下不可用。

警告:使用局部离群因子的新奇点检测

novelty 设置为 True 时,请注意,您必须只能对新的未见过的数据而不是训练样本使用predict, decision_functionscore_samples方法,因为这将导致错误的结果。训练样本的异常得分总可以通过negative_outlier_factor_属性获得。

使用局部离群因子的新奇点检测如下所示。

https://scikit-learn.org/stable/_images/sphx_glr_plot_lof_novelty_detection_0011.png

© 2007 - 2019, scikit-learn 开发人员 (BSD 许可证). 此页显示源码