异常检测介绍

异常检测

1、什么是离群值(outlier)

离群值是与其他数据有显著差异的数据点。
Hawkins defined 1 an outlier as follows:
“An outlier is an observation which deviates so much from the other observations as to arouse suspicions that it was generated by a different mechanism.”
异常值(outliers)在数据挖掘和统计学文献中也被称为abnormalities、discordants、 deviants或 anomalies。在大多数应用场景中,数据是由一个或多个生成过程创建的,这些过程可以反映系统中的活动,也可以反映收集到的关于实体的观察结果。当生成过程行为异常时,会导致产生离群值。因此,异常值通常包含有关影响数据生成过程的系统和实体的异常特征的有用信息。对这些不寻常特性的认识提供了针对具体应用的有用见解。一些例子如下:

  • 入侵检测系统: 在许多计算机系统中,收集有关操作系统调用、网络流量或其他用户操作的不同类型的数据。这些数据可能显示恶意行为导致的不寻常行为。这种活动的识别被称为入侵检测。
  • 信用卡欺诈: 信用卡欺诈已经变得越来越普遍,因为敏感信息(如信用卡号码)更容易被泄露。在许多情况下,未经授权使用信用卡可能表现出不同的模式,例如从特定地点疯狂购物或进行非常大的交易。这种模式可用于检测信用卡交易数据中的异常值。
  • 有趣的传感器事件: 在许多现实世界的应用中,传感器经常用于跟踪各种环境和位置参数。潜在模式的突然变化可能代表感兴趣的事件。事件检测是传感器网络领域主要的激励应用之一。
  • 医学诊断: 在许多医学应用中,数据是从各种设备中收集的,如磁共振成像(MRI)扫描、正电子发射计算机断层扫描(PET)扫描或心电图(ECG)时间序列。这些数据中不寻常的模式通常反映了疾病状况。
  • 执法: 异常检测在执法中发现了大量的应用,特别是在那些只能通过一个实体的多次行动才能发现不寻常模式的案例中。要确定金融交易、交易活动或保险索赔中的欺诈行为,通常需要在犯罪实体的行为所产生的数据中识别不寻常的模式。
  • 地球科学: 通过卫星或遥感等各种机制收集了大量关于天气模式、气候变化或土地覆盖模式的时空数据。这些数据中的异常现象提供了关于人类活动或环境趋势的重要见解,这些可能是潜在的原因。

在所有这些应用程序中,数据都有一个“正常”模型,并且异常被识别为偏离正常模型的偏差。正常数据点有时也称为 inliers。在入侵或欺诈检测等应用中,离群值对应的是多个数据点的序列,而不是单个数据点。例如,欺诈事件可能经常反映个人在特定序列中的行为。序列的特异性与识别异常事件有关。这种异常也称为集体异常,因为它们只能从一组数据点或数据点序列中集体推断出来。这种集体异常现象往往是不寻常事件产生的异常活动模式的结果。
异常检测算法的输出可以是以下两种类型之一:

  • 离群值得分:大多数异常检测/值算法都会输出一个量化每个数据点的“离群值”水平的得分。这个评分也可以用来对数据点按照它们的离群值趋势进行排序。这是一种非常一般的输出形式,它保留了某一特定算法提供的所有信息,但没有提供应被视为离群值的少量数据点的简明摘要。
  • 二进制标签: 第二种输出类型是二进制标签,指示数据点是否是离群值。虽然有些算法可能直接返回二进制标签,但是离群值得分也可以转换为二进制标签。这通常是通过在离群值上设置阈值来实现的,阈值是根据得分的统计分布来选择的。二进制标记比计分机制包含的信息要少,但它是实际应用中决策常常需要的最终结果。

2、基本异常检测模型

从分析师的角度来看,异常检测模型的可解释性是极其重要的。通常需要确定为什么应该将特定数据点视为异常值,因为它为分析人员提供了有关特定应用程序场景中所需诊断的进一步提示。这个过程也被称为发现关于异常值的内涵知识2或异常检测和描述3的过程。不同的模型具有不同程度的可解释性。通常,使用原始属性并对数据使用较少转换的模型(例如,主成分分析)具有较高的可解释性。权衡的结果是,数据转换常常增强异常点和正常数据点之间的对比,而牺牲了可解释性。因此,在选择特定模型进行离群值分析时,记住这些因素至关重要。

2.1 概率和统计模型

在概率模型和统计模型中,数据以一个封闭的概率分布模型的形式建模,并且学习这个模型的参数。因此,这里的关键假设是关于执行建模的数据分布的具体选择。例如,高斯混合模型假设数据是生成过程的输出,其中每个点都属于 k 高斯簇中的一个。这些高斯分布的参数是学习使用期望最大化(EM)算法对观测数据,使概率(或似然)的过程产生的数据尽可能大。该方法的一个关键输出是数据点对不同聚类的隶属度概率,以及基于密度的对模型分布的拟合。这为异常值建模提供了一种自然的方法,因为具有非常低拟合值的数据点可能被视为异常值。在实际应用中,这些拟合值的对数被用作离群值得分,因为离群值更倾向于使用对数拟合作为极值出现,可以对这些拟合值应用极值测试来识别异常值。
概率模型的一个主要优点是,它们可以很容易地应用于几乎任何数据类型(或混合数据类型) ,只要每个混合组件都有适当的生成模型。例如,如果数据是类别型的,那么可以用一个离散的伯努利分布模型来模拟混合物的每个成分。对于不同类型属性的混合,可以使用特定于属性的生成组件的乘积。由于这样的模型与概率一起工作,数据规范化的问题已经被生成性假设所解释。因此,概率模型提供了一个基于 EM算法的通用框架,可以相对容易地应用于任何特定的数据类型。对于其他许多模型来说,情况并非如此。
概率模型的一个缺点是,它们试图将数据适应于某种特定的分布,而这种分布有时可能并不合适。此外,随着模型参数数量的增加,过拟合现象越来越普遍。在这种情况下,离群值可能适合正常数据的底层模型。许多参数模型也很难用内涵知识来解释,特别是当模型的参数不能直观地以底层属性的形式呈现给分析师时。这可能会破坏异常检测的一个重要目的,即提供对异常数据生成过程的诊断性理解。

2.2 线性模型

在这里插入图片描述

这些方法利用线性相关性对低维子空间的数据建模4。例如,在图1.4中,数据沿着2维空间中的1维线对齐。通过这些点的最佳直线是通过回归分析来确定的。通常,最小二乘拟合用于确定最佳的低维超平面。数据点与这个超平面的距离被用来量化离群值得分,因为它们量化了正常数据模型的偏差。极值分析可以应用于这些得分,以确定离群值。例如,在图1.4的二维例子中,数据点{(xi,yi) ,i ∈{1… n }按两个系数 a 和 b 可以创建如下:
在这里插入图片描述
在这里插入图片描述

2.3 基于邻近度的模型

基于邻近度的方法的思想是将离群点基于相似度或距离函数从剩余数据中分离出来的模型。基于邻近度的方法是孤立点分析中最常用的方法之一,包括基于邻近度的聚类方法、基于密度的聚类方法和基于最近邻方法。在聚类和其他基于密度的方法中,直接找到数据中的密集区域,并将离群点定义为不在这些密集区域中的点。或者,可以将离群值定义为远离稠密区域的点。聚类方法和基于密度的方法的主要区别是聚类方法分割数据点,而基于密度的方法如直方图分割数据空间。这是因为后一种情况的目标是估计数据空间中测试点的密度,这最好通过空间分割来实现。

2.4 信息论模型

前面提到的许多孤立点分析模型使用各种形式的数据汇总,例如生成概率模型参数、聚类或低维表示超平面。这些模型隐式地生成一个小的数据摘要,偏离这个摘要的地方被标记为离群值。信息理论测度也是基于同样的原则,但是是间接的。其思想是,离群值增加了描述数据集所需的最小代码长度(即摘要的最小长度) ,因为它们表示了对数据总结的自然尝试的偏离。

3、异常检测常用开源库

3.1 Scikit-learn

Scikit-learn是一个Python语言的开源机器学习库,支持4种异常检测方法,LOF,IsolationForest, OneClassSVM,EllipticEnvelope。

3.2 PyOD

Python Outlier Detection(PyOD)是当下最流行的Python异常检测工具库,其主要亮点包括:

  • 包括近20种常见的异常检测算法,比如经典的LOF/LOCI/ABOD以及最新的深度学习如对抗生成模型(GAN)和集成异常检测(outlier ensemble)
  • 支持不同版本的Python:包括2.7和3.5+;支持多种操作系统:windows,macOS和Linux
  • 简单易用且一致的API,只需要几行代码就可以完成异常检测,方便评估大量算法
  • 使用并行化(parallelization)进行优化,加速算法运行及扩展性(scalability),可以处理大量数据

4、实例

4.1 KNN

通过一个例子学习pyod库的基本操作,值得一提的是,pyod库的api设计几乎完全参考了scikit-learn,对于使用者来说学习成本极低。
简单来说,一个完整的pyod训练模型分为以下几步:

扫描二维码关注公众号,回复: 12949071 查看本文章
  • 生成数据集或引用现成数据集
  • 在训练集上训练模型
  • 预测测试集的结果
  • 给出模型评估分数
  • 可视化模型结果(高维数据集难以可视化)

from pyod.models.knn import KNN
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize

contamination = 0.1 # percentage of outliers
n_train = 200 # number of training points
n_test = 100 # number of testing points

#生成虚拟数据
X_train, y_train, X_test, y_test =
generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42)

#训练KNN模型
clf_name = ‘KNN’
clf = KNN()
clf.fit(X_train) # 注意训练模型的时候,不需要输入y参数

#得到训练标签和训练分数
y_train_pred = clf.labels_ # 0正常,1异常
y_train_scores = clf.decision_scores_ # 数值越大越异常

#用训练好的模型预测测试数据的标签和分数
y_test_pred = clf.predict(X_test)
y_test_scores = clf.decision_function(X_test)

#评估并打印结果
print("\nOn Training Data:")
evaluate_print(clf_name, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf_name, y_test, y_test_scores)

#可视化模型效果
visualize(clf_name, X_train, y_train, X_test, y_test, y_train_pred,
y_test_pred, show_figure=True, save_figure=True)

在这里插入图片描述

4.2 Isolation Forest

4.2.1 使用Scikit-learn实现Isolation Forest

import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import IsolationForest
#获得伪随机数生成器
rng = np.random.RandomState(42)

#以给定的形状创建一个数组,数组元素来符合标准正态分布N(0,1)
X = 0.3 * rng.randn(100, 2)
#np.r是按列连接两个矩阵,就是把两矩阵上下相加,要求列数相等
X_train = np.r_[X + 1, X - 3, X - 5, X + 6]
print(‘X_train’,X_train)

#再生成一组有规律的数据
X = 0.3 * rng.randn(50, 2)
X_test = np.r_[X + 1, X - 3, X - 5, X + 6]
print(‘X_test’,X_test)

#生成一组异常数据
#随机生成-8-8之间(20,2)的出界数组
X_outliers = rng.uniform(low=-8, high=8, size=(20, 2))
print(‘X_outliers’,X_outliers)
#生成模型
clf = IsolationForest(max_samples=100)
clf.fit(X_train)
#生成训练数据预测值
y_pred_train = clf.predict(X_train)
print(‘y_pred_train’,y_pred_train)
#生成测试数据预测值
y_pred_test = clf.predict(X_test)
print(‘y_pred_test’,y_pred_test)
#生成出界数据预测值
y_pred_outliers = clf.predict(X_outliers)
print(‘y_pred_outliers’,y_pred_outliers)
#画图
xx, yy = np.meshgrid(np.linspace(-8, 8, 50), np.linspace(-8, 8, 50))
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

plt.title(“IsolationForest”)
plt.contourf(xx, yy, Z, cmap=plt.cm.Blues_r)

b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c=‘white’)
b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c=‘green’)
c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c=‘red’)
plt.axis(‘tight’)
plt.xlim((-8, 8))
plt.ylim((-8, 8))
plt.legend([b1, b2, c],
[“training observations”,
“new regular observations”, “new abnormal observations”],
loc=“upper left”)
plt.show()
在这里插入图片描述

4.2.2 使用PyOD实现Isolation Forest

from future import division
from future import print_function
import os
import sys
from pyod.models.iforest import IForest
from pyod.utils.data import generate_data
from pyod.utils.data import evaluate_print
from pyod.utils.example import visualize
if name == “main”:
contamination = 0.1 # 离群值百分比
n_train = 200 # 训练点数
n_test = 100 # 测试点数
#生成样本数据
X_train, y_train, X_test, y_test =
generate_data(n_train=n_train,
n_test=n_test,
n_features=2,
contamination=contamination,
random_state=42)
# 训练
clf = IForest()
clf.fit(X_train)

if name == “main”:
contamination = 0.1 # 离群值百分比
n_train = 200 # 训练点数
n_test = 100 # 测试点数

# 生成样本数据
X_train, y_train, X_test, y_test = \
    generate_data(n_train=n_train,
                  n_test=n_test,
                  n_features=2,
                  contamination=contamination,
                  random_state=42)

# 训练
clf = IForest()
clf.fit(X_train)

# 得到训练数据的预测标签和离群值
y_train_pred = clf.labels_  # 二元标签(0: inliers, 1: outliers)
y_train_scores = clf.decision_scores_  

# 获取测试数据的预测值
y_test_pred = clf.predict(X_test)  # outlier labels (0 or 1)
y_test_scores = clf.decision_function(X_test)  # 异常分数

# 评估并输出结果
print("\nOn Training Data:")
evaluate_print(clf, y_train, y_train_scores)
print("\nOn Test Data:")
evaluate_print(clf, y_test, y_test_scores)

# 可视化结果
visualize(clf, X_train, y_train, X_test, y_test, y_train_pred,
          y_test_pred, show_figure=True, save_figure=False)

On Training Data:
IForest(behaviour=‘old’, bootstrap=False, contamination=0.1, max_features=1.0,
max_samples=‘auto’, n_estimators=100, n_jobs=1, random_state=None,
verbose=0) ROC:0.9956, precision @ rank n:0.85

On Test Data:
IForest(behaviour=‘old’, bootstrap=False, contamination=0.1, max_features=1.0,
max_samples=‘auto’, n_estimators=100, n_jobs=1, random_state=None,
verbose=0) ROC:0.9967, precision @ rank n:0.9
在这里插入图片描述

4.3 One Class SVM

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))
#Generate train data
X = 0.3 * np.random.randn(100, 2)
X_train = np.r_[X + 2, X - 2]
#Generate some regular novel observations
X = 0.3 * np.random.randn(20, 2)
X_test = np.r_[X + 2, X - 2]
#Generate some abnormal novel observations
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)
n_error_train = y_pred_train[y_pred_train == -1].size
n_error_test = y_pred_test[y_pred_test == -1].size
n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size

#plot the line, the points, and the nearest vectors to the plane
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

plt.title(“Novelty Detection”)
plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap=plt.cm.PuBu) # 绘制异常样本的区域
a = plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors=‘darkred’) # 绘制正常样本和异常样本的边界
plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors=‘palevioletred’) # 绘制正常样本的区域
s = 40
b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c=‘white’, s=s, edgecolors=‘k’)
b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c=‘blueviolet’, s=s,
edgecolors=‘k’)
c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c=‘gold’, s=s,
edgecolors=‘k’)
plt.axis(‘tight’)
plt.xlim((-5, 5))
plt.ylim((-5, 5))
plt.legend([a.collections[0], b1, b2, c],
[“learned frontier”, “training observations”,
“new regular observations”, “new abnormal observations”],
loc=“upper left”,
prop=matplotlib.font_manager.FontProperties(size=11))
plt.xlabel(
"error train: %d/200 ; errors novel regular: %d/40 ; "
“errors novel abnormal: %d/40”
% (n_error_train, n_error_test, n_error_outliers))
plt.show()

在这里插入图片描述

4.4 Local Outlier Factor

import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import LocalOutlierFactor
from scipy import stats

#构造训练样本
n_samples = 200 # 样本总数
outliers_fraction = 0.25 # 异常样本比例
n_inliers = int((1. - outliers_fraction) * n_samples)
n_outliers = int(outliers_fraction * n_samples)

rng = np.random.RandomState(42)
X = 0.3 * rng.randn(n_inliers // 2, 2)
X_train = np.r_[X + 2, X - 2] # 正常样本
X_train = np.r_[X_train, np.random.uniform(low=-6, high=6, size=(n_outliers, 2))] # 正常样本加上异常样本

#fit the model
clf = LocalOutlierFactor(n_neighbors=35, contamination=outliers_fraction)
y_pred = clf.fit_predict(X_train)
scores_pred = clf.negative_outlier_factor_
threshold = stats.scoreatpercentile(scores_pred, 100 * outliers_fraction) # 根据异常样本比例,得到阈值,用于绘图

#plot the level sets of the decision function
xx, yy = np.meshgrid(np.linspace(-7, 7, 50), np.linspace(-7, 7, 50))
Z = clf.decision_function(np.c[xx.ravel(), yy.ravel()]) # 类似scores_pred的值,值越小越有可能是异常点
Z = Z.reshape(xx.shape)

plt.title(“Local Outlier Factor (LOF)”)
#plt.contourf(xx, yy, Z, cmap=plt.cm.Blues_r)

plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), threshold, 7), cmap=plt.cm.Blues_r) # 绘制异常点区域,值从最小的到阈值的那部分
a = plt.contour(xx, yy, Z, levels=[threshold], linewidths=2, colors=‘red’) # 绘制异常点区域和正常点区域的边界
plt.contourf(xx, yy, Z, levels=[threshold, Z.max()], colors=‘palevioletred’) # 绘制正常点区域,值从阈值到最大的那部分

b = plt.scatter(X_train[:-n_outliers, 0], X_train[:-n_outliers, 1], c=‘white’,
s=20, edgecolor=‘k’)
c = plt.scatter(X_train[-n_outliers:, 0], X_train[-n_outliers:, 1], c=‘black’,
s=20, edgecolor=‘k’)
plt.axis(‘tight’)
plt.xlim((-7, 7))
plt.ylim((-7, 7))
plt.legend([a.collections[0], b, c],
[‘learned decision function’, ‘true inliers’, ‘true outliers’],
loc=“upper left”)
plt.show()
在这里插入图片描述


  1. D. Hawkins. Identification of Outliers, Chapman and Hall, 1980. ↩︎

  2. E. Knorr and R. Ng. Finding Intensional Knowledge of Distance-Based Outliers. VLDB Conference, 1999. ↩︎

  3. L. Akoglu, E. Muller, and J Vreeken. ACM KDD Workshop on Outlier Detection and Description, 2013. http://www.outlieranalytics.org/odd13kdd/ ↩︎

  4. P. Rousseeuw and A. Leroy. Robust Regression and Outlier Detection. Wiley, 2003. ↩︎

猜你喜欢

转载自blog.csdn.net/weixin_43595036/article/details/112488120