sklearn中的异常检测

参考资料:https://blog.csdn.net/hustqb/article/details/75216241
http://sklearn.apachecn.org/cn/0.19.0/modules/outlier_detection.html

概述

本节内容主要来自sklearn的官方文档。本节内容属于无监督学习。

许多应用需要能够对新观测进行判断,判断其是否与现有观测服从同一分布(即新观测是否为内围值),相反则被认为不服从同一分布(即新观测为异常值)。 通常,这种能力被用于清洗实际的数据集。

这种能力分为两类:
- 新奇检测: 训练数据未被异常值污染(没有异常值). sklearn中的这类算法是svm.OneClassSVM
- 异常值检测: 训练数据包含异常值,我们需要拟合出训练数据的分布规律,忽略有偏差的观测。sklearn中的这类算法有:椭圆模型拟合-covariance.EllipticEnvelope、隔离森林-ensemble.IsolationForest、局部异常系数-neighbors.LocalOutlierFactor

scikit-learn项目提供了一套可用于新奇或异常值检测的机器学习工具。 该策略是以无监督的方式学习数据中的对象来实现的:

estimator.fit(X_train)

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

estimator.predict(X_test)

内围值被标记为1,而异常值被标记为-1。

Novelty Detection(新奇检测)

One-Class SVM(一类支持向量机)已经由 Schölkopf 等人采用以实现新奇检测,并在 支持向量机 模块的 svm.OneClassSVM 对象中实现。需要选择 kernel 和 scalar 参数来定义边界。 通常选择 RBF kernel。

svm.OneClassSVM官方的代码例子比较长,我摘抄了一段。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.font_manager
from sklearn import svm

xx, yy = np.meshgrid(np.linspace(-5, 5, 500), np.linspace(-5, 5, 500))
# 生成训练数据
X = 0.3 * np.random.randn(100, 2)
X_train = np.r_[X + 2, X - 2] #形成两簇
# 生成测试数据,和训练数据类似,生成两簇。
X = 0.3 * np.random.randn(20, 2)
X_test = np.r_[X + 2, X - 2] #np.r_是合并两个矩阵,两个矩阵分别是生成矩阵的偏移
# 异常数据
X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2))

# fit the model
clf = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=0.1)
clf.fit(X_train)
y_pred_train = clf.predict(X_train)
y_pred_test = clf.predict(X_test)
y_pred_outliers = clf.predict(X_outliers)
print('y_pred_train:{}, \ny_pred_test:{},\n y_pred_outliers:{}'.format(y_pred_train, y_pred_test, y_pred_outliers))

官方输出的图为:
image

终端输出为:

y_pred_train:[ 1  1  1  1  1 -1  1  1  1  1 -1  1 -1  1  1  1  1  1  1  1  1  1  1  1
  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 -1  1  1  1
  1  1 -1  1  1  1  1  1 -1  1  1  1  1  1  1  1  1  1  1  1 -1 -1  1  1
 -1  1 -1  1  1  1  1 -1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
  1  1  1  1  1  1  1  1  1 -1  1  1  1  1 -1  1 -1  1  1  1  1  1  1  1
 -1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
  1  1  1  1  1  1  1  1  1  1  1  1 -1 -1  1  1  1  1  1  1  1  1  1  1
 -1 -1  1  1  1  1  1  1  1  1  1 -1  1  1  1  1  1  1  1  1  1  1  1  1
  1  1  1  1  1  1  1  1], 
y_pred_test:[ 1 -1  1  1  1  1  1  1  1  1  1 -1  1  1  1  1  1  1  1  1  1 -1  1  1
  1  1 -1  1  1  1  1 -1  1  1  1  1  1  1  1  1],
y_pred_outliers:[-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1]

之所以有训练样本被分到线外,是因为用nu=0.1指定有10%属于异常样本,把这个值调小,可以减少训练样本的错分。但是同时包络线范围变大,很多错误样本被分进来了。

Outlier Detection(异常值检测)

异常值检测类似于新奇检测,其目的是将内围观测的中心与一些被称为 “异常值” 的污染数据进行分离。 然而,在异常值检测的情况下,我们没有干净且适用于训练任何工具的数据集来代表内围观测的总体。
下面几个方法,官方的例子在这里

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

实现异常值检测的一种常见方式是假设内围数据来自已知分布(例如,数据服从高斯分布)。

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

个人理解:这种方式就是多元高斯的异常检测。吴恩达视频课程里对后来要检测的每个样本输出一个概率,要用少量的标记样本寻找异常的概率阈值。而这里直接在参数里指定了异常数据的比例,用这部分离中心比较远的样本点决定正常和异常的阈值(外围线)。

Isolation Forest(隔离森林)

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

Local Outlier Factor(局部异常系数)

对中等高维数据集实现异常值检测的另一种有效方法是使用局部异常系数(LOF)算法。

neighbors.LocalOutlierFactor (LOF)算法计算出反映观测异常程度的得分(称为局部异常系数)。 它测量给定数据点相对于其邻近点的局部密度偏差。 算法思想是检测出具有比其邻近点明显更低密度的样本。
实际上,局部密度从 k 个最近邻得到。 观测数据的 LOF 得分等于其 k 个最近邻的平均局部密度与其本身密度的比值:正常情况预期具有与其近邻类似的局部密度,而异常数据 则预计比局部密度要小得多。

个人理解:每个样本点都计算和k个最近邻的距离之和,这个距离之和作为局部密度度量值。k个邻居都有自己的局部密度,用k个邻居的局部密度平均值和自己局部密度相除得到LOF,小于一个阈值则为异常。这个阈值怎么找呢?实例化时传入的参数contamination (default=0.1)可以用来计算这个异常值。
别人讲解LOF原理的一篇博客:https://blog.csdn.net/wangyibo0201/article/details/51705966

LOF 算法的优点是考虑到数据集的局部和全局属性:即使在异常样本具有不同潜在密度的数据集中,它也能够表现得很好。 问题不在于样本是如何被分离的,而是样本与周围近邻的分离程度有多大。

对比

下面几个方法,官方的例子在这里

可以看到,无论双峰还是单峰,LOF的效果都是不错的。
image
image

总结

异常检测的4个算法都有contamination 这个参数,用来指定污染数据的比例。这个比例最终能决定正常数据和异常数据分界线。

猜你喜欢

转载自blog.csdn.net/yuanlulu/article/details/81226518