使用PyOD库在Python中学习异常检测

Introduction

我最新的数据科学项目涉及预测特定商店中每种产品的销售情况。 有几种方法可以解决这个问题。 但无论我使用哪种型号,我的准确度分数都不会提高。

我花了一些时间检查数据后才发现问题 - 异常值!

使用PyOD库在Python中学习异常检测_第1张图片

这是我们经常忽略的一个错误。诱惑是开始根据您给出的数据建立模型。但这实际上是让自己陷入失败之中。

数据探索没有捷径可走。如果您跳过数据科学项目的这个阶段,构建模型只会让您到目前为止。经过一段时间后,您将达到准确度上限 - 模型的性能不会让步。

数据探索包括许多因素,例如变量识别,处理缺失值,特征工程等。检测和处理异常值也是数据探索阶段的主要因素。输入的质量决定了输出的质量!

PyOD是一个用于检测数据中异常值的库。它提供对20多种不同算法的访问,以检测异常值,并兼容Python 2和3.绝对的宝石!

在本文中,我将带您了解异常值以及如何使用Python中的PyOD检测异常值。

本文假设您具有机器学习算法和Python语言的基本知识。 你可以参考这篇文章 - “机器学习要点”,了解 或刷新这些概念。

Table of Contents

  • 1什么是异常值?
  • 2为什么我们需要检测异常值?
  • 3为什么我们应该使用PyOD进行离群检测?
  • 4 PyOD库的功能
  • 5在Python中安装PyOD
  • 6 PyOD中使用的一些异常值检测算法
  • PyOD提供的7个额外实用程序
  • 8在Python中实现PyoD

What is an Outlier?

异常值是任何数据点,与数据集中的其余观察结果差别很大。 让我们看一些真实的例子来理解异常值检测:

  • 当一名学生平均超过90%而其余学生达到70%时 - 一个明确的异常值
  • 在分析某个客户的购买模式时,事实证明突然出现了非常高的价值。 虽然他/她的大部分交易都低于卢比。 10,000,此条目是卢比。1,00,000。 它可能是一个电子产品购买 - 无论什么原因,它是整体数据的异常值
  • Usain Bolt怎么样? 当你考虑到大多数运动员时,那些破纪录的短跑绝对是异常值
    使用PyOD库在Python中学习异常检测_第2张图片

存在异常值的原因有很多。 也许分析师在数据输入中出错,或者机器在测量中引起错误,或者异常值甚至可能是故意的! 有些人不想透露他们的信息,因此在表格中输入虚假信息。

异常值有两种类型:单变量多变量。 单变量异常值是仅由一个变量中的极值组成的数据点,而多变量异常值是至少两个变量的组合异常分数。 假设您有三个不同的变量 - X,Y,Z。如果您在三维空间中绘制这些变量的图形,它们应该形成一种云。 位于此云之外的所有数据点都将是多变量异常值。

我强烈建议您阅读这本关于数据探索的精彩指南,其中详细介绍了异常值。

Why do we need to Detect Outliers?

异常值可以极大地影响我们的分析和统计建模的结果。 查看下面的图像,可视化出现异常值时模型发生的情况与处理异常值时的情况:

使用PyOD库在Python中学习异常检测_第3张图片

但这里是警告 - 离群值并不总是坏事。 了解这一点非常重要。 简单地从数据中删除异常值而不考虑它们如何影响结果是一种灾难。

“异常值不一定是坏事。 这些只是不遵循相同模式的观察
  和其他人一样。 但事实上异常值非常有趣。 例如,如果在生物学中
   实验,一只老鼠没有死,而其他一切都是,那么理解为什么会非常有趣。
   这可能会带来新的科学发现。 因此,检测异常值非常重要。“
                                                                                                        – Pierre Lafaye de Micheaux, Author and Statistician

我们倾向于使用简单的方法,如箱形图,直方图和散点图来检测异常值。 但是,专用异常值检测算法在处理大量数据并需要在较大数据集中执行模式识别的方法中非常有价值。

金融中的欺诈检测和网络安全中的入侵检测等应用需要密集而准确的技术来检测异常值。 你能想象如果你发现一个离群值并且结果是真的那么会有多尴尬吗?

PyOD库可以介入以弥补这一差距。 让我们看看它的全部内容。

Why should we use PyOD for Outlier Detection?

许多异常检测包存在于各种编程语言中。 我特别发现这些语言在R中很有用。但是当我切换到Python时,显然缺少异常值检测库。 这怎么可能?!

像PyNomaly这样的现有实现并不是专门为异常值检测而设计的(虽然它仍然值得一试!)。 为填补这一空白,Yue Zhao,Zain Nasrullah和Zheng Li设计并实施了PyOD库。

PyOD是一个可扩展的Python工具包,用于检测多变量数据中的异常值。 它可以在一个详细记录API下访问大约20个离群值检测算法。

Features of PyOD

PyOD有几个优点,并且有许多有用的功能。 这是我挑选的一堆:

  • 开源,包含各种算法的详细文档和示例
  • 支持高级模型,包括神经网络,深度学习和异常集合
  • 使用Numba和joblib优化JIT(即时)和并行化的性能
  • 兼容Python 2和3

Installing PyOD in Python

Time to power up our Python notebooks! Let’s first install PyOD on our machines:

pip install pyod
pip install --upgrade pyod  # to make sure that the latest version is installed!

就如此容易!

请注意,PyOD还包含一些基于神经网络的模型,这些模型在Keras中实现。 PyOD不会自动安装Keras或TensorFlow。 如果要使用基于神经网络的模型,则需要手动安装Keras和其他库。

Outlier Detection Algorithms used in PyOD

让我们看看为PyOD提供动力的异常值检测算法。 它很好并且很好地实现了PyOD,但我觉得理解它在底层是如何工作同样重要。 当您在数据集上使用它时,这将为您提供更大的灵活性。

注意:我们将在本节中使用术语外围分数。 这意味着每个模型以某种方式对数据点进行评分而不是使用阈值来确定该点是否是异常值。

Angle-Based Outlier Detection (ABOD)

  • 它考虑每个点与其邻居之间的关系。 它没有考虑这些邻居之间的关系。 其加权余弦分数与所有邻居的方差可视为偏离分数
  • ABOD在多维数据上表现良好
  • PyOD提供两种不同版本的ABOD:
    • 快速ABOD:使用k近邻来近似
    • 原始ABOD:考虑所有具有高时间复杂性的训练点

k-Nearest Neighbors Detector

  • 对于任何数据点,到第k个最近邻居的距离可以被视为远离分数
  • PyOD支持三个kNN探测器:
    • 最大:使用第k个邻居的距离作为离群值
    • 均值:使用所有k个邻居的平均值作为离群值得分
    • 中位数:使用与邻居的距离的中位数作为离群值得分

Isolation Forest

  • 它在内部使用scikit-learn库。 在此方法中,使用一组树完成数据分区。 隔离森林提供了一个异常分数,用于查看结构中点的隔离程度。 然后使用异常分数来识别来自正常观察的异常值
  • 隔离森林在多维数据上表现良好

Histogram-based Outlier Detection

  • 这是一种有效的无监督方法,它假设特征独立并通过构建直方图来计算异常值
  • 它比多变量方法快得多,但代价是精度较低

Local Correlation Integral (LOCI)

  • LOCI对于检测异常值和异常值组非常有效。 它为每个点提供LOCI图,总结了该点周围区域内数据的大量信息,确定了簇,微簇,它们的直径以及它们的簇间距离
  • 现有的异常检测方法都不能匹配此功能,因为它们只为每个点输出一个数字

Feature Bagging

  • 功能装袋检测器在数据集的各种子样本上安装了许多基本检测器。 它使用平均或其他组合方法来提高预测精度
  • 默认情况下,Local Outlier Factor(LOF)用作基本估算器。 但是,任何估计器都可以用作基本估计器,例如kNN和ABOD
  • 特征装袋首先通过随机选择特征子集来构造n个子样本。 这带来了基本估计的多样性。 最后,通过平均或取所有基本检测器的最大值来生成预测分数

Clustering Based Local Outlier Factor

  • 它将数据分为小型集群和大型集群。 然后根据点所属的簇的大小以及到最近的大簇的距离来计算异常分数

Extra Utilities provided by PyOD

  • 函数** generate_data **可用于生成具有异常值的随机数据。 内部数据由多元高斯分布生成,异常值由均匀分布生成。
  • 我们可以在数据集中提供我们自己的异常值分数值和我们想要的样本总数。 我们将使用此实用程序函数在实现部分中创建数据。

Implementation of PyOD

足够的谈话 - 让我们看看一些行动。 在本节中,我们将在Python中实现PyOD库。 我将使用两种不同的方法来演示PyOD:

  • 使用模拟数据集
  • 使用真实世界的数据集 - 大市场销售挑战

PyOD on a Simulated Dataset

First, let’s import the required libraries:

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib.font_manager

现在,我们将导入我们想要用来检测数据集中异常值的模型。 我们将使用ABOD(基于角度的异常值检测器)和KNN(K最近邻居):

from pyod.models.abod import ABOD
from pyod.models.knn import KNN

现在,我们将创建一个带有异常值的随机数据集并绘制它。

from pyod.utils.data import generate_data, get_outliers_inliers

#generate random data with two features
X_train, Y_train = generate_data(n_train=200,train_only=True, n_features=2)

# by default the outlier fraction is 0.1 in generate data function 
outlier_fraction = 0.1

# store outliers and inliers in different numpy arrays
x_outliers, x_inliers = get_outliers_inliers(X_train,Y_train)

n_inliers = len(x_inliers)
n_outliers = len(x_outliers)

#separate the two features and use it to plot the data 
F1 = X_train[:,[0]].reshape(-1,1)
F2 = X_train[:,[1]].reshape(-1,1)

# create a meshgrid 
xx , yy = np.meshgrid(np.linspace(-10, 10, 200), np.linspace(-10, 10, 200))

# scatter plot 
plt.scatter(F1,F2)
plt.xlabel('F1')
plt.ylabel('F2') 

创建一个字典并添加要用于检测异常值的所有模型:

classifiers = {
     'Angle-based Outlier Detector (ABOD)'   : ABOD(contamination=outlier_fraction),
     'K Nearest Neighbors (KNN)' :  KNN(contamination=outlier_fraction)
}

将数据拟合到我们在字典中添加的每个模型,然后,查看每个模型如何检测异常值:

#set the figure size
plt.figure(figsize=(10, 10))

for i, (clf_name,clf) in enumerate(classifiers.items()) :
    # fit the dataset to the model
    clf.fit(X_train)

    # predict raw anomaly score
    scores_pred = clf.decision_function(X_train)*-1

    # prediction of a datapoint category outlier or inlier
    y_pred = clf.predict(X_train)

    # no of errors in prediction
    n_errors = (y_pred != Y_train).sum()
    print('No of Errors : ',clf_name, n_errors)

    # rest of the code is to create the visualization

    # threshold value to consider a datapoint inlier or outlier
    threshold = stats.scoreatpercentile(scores_pred,100 *outlier_fraction)

    # decision function calculates the raw anomaly score for every point
    Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) * -1
    Z = Z.reshape(xx.shape)

    subplot = plt.subplot(1, 2, i + 1)

    # fill blue colormap from minimum anomaly score to threshold value
    subplot.contourf(xx, yy, Z, levels = np.linspace(Z.min(), threshold, 10),cmap=plt.cm.Blues_r)

    # draw red contour line where anomaly score is equal to threshold
    a = subplot.contour(xx, yy, Z, levels=[threshold],linewidths=2, colors='red')

    # fill orange contour lines where range of anomaly score is from threshold to maximum anomaly score
    subplot.contourf(xx, yy, Z, levels=[threshold, Z.max()],colors='orange')

    # scatter plot of inliers with white dots
    b = subplot.scatter(X_train[:-n_outliers, 0], X_train[:-n_outliers, 1], c='white',s=20, edgecolor='k') 
    # scatter plot of outliers with black dots
    c = subplot.scatter(X_train[-n_outliers:, 0], X_train[-n_outliers:, 1], c='black',s=20, edgecolor='k')
    subplot.axis('tight')

    subplot.legend(
        [a.collections[0], b, c],
        ['learned decision function', 'true inliers', 'true outliers'],
        prop=matplotlib.font_manager.FontProperties(size=10),
        loc='lower right')

    subplot.set_title(clf_name)
    subplot.set_xlim((-10, 10))
    subplot.set_ylim((-10, 10))
plt.show() 

Looking good!

PyOD on the Big Mart Sales Problem

现在,让我们看看PyOD如何在着名的大市场销售问题上做.

继续从上面的链接下载数据集。 让我们从导入所需的库并加载数据开始:

import pandas as pd
import numpy as np

# Import models
from pyod.models.abod import ABOD
from pyod.models.cblof import CBLOF
from pyod.models.feature_bagging import FeatureBagging
from pyod.models.hbos import HBOS
from pyod.models.iforest import IForest
from pyod.models.knn import KNN
from pyod.models.lof import LOF
# reading the big mart sales training data
df = pd.read_csv("train.csv")

让我们绘制Item MRP vs Item Outlet Sales以了解数据:

df.plot.scatter('Item_MRP','Item_Outlet_Sales')

项目插座销售的范围是0到12000,项目MRP是0到250.我们将这两个功能缩小到0到1之间的范围。这是创建可解释的可视化所必需的(它将变得太紧张) 除此以外)。 对于此数据,使用相同的方法将花费更多时间来创建可视化。

注意:如果您不想要可视化,则可以使用相同的比例来预测某个点是否为异常值。

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(0, 1))
df[['Item_MRP','Item_Outlet_Sales']] = scaler.fit_transform(df[['Item_MRP','Item_Outlet_Sales']])
df[['Item_MRP','Item_Outlet_Sales']].head()


将这些值存储在NumPy数组中,以便以后在我们的模型中使用:

X1 = df['Item_MRP'].values.reshape(-1,1)
X2 = df['Item_Outlet_Sales'].values.reshape(-1,1)

X = np.concatenate((X1,X2),axis=1)

再次,我们将创建一个字典。 但这一次,我们将添加更多模型,并了解每个模型如何预测异常值。

您可以根据问题和对数据的理解来设置异常值分数的值。 在我们的示例中,我想检测5%与其他数据不相似的观察结果。 所以,我要将异常分数的值设置为0.05。

random_state = np.random.RandomState(42)
outliers_fraction = 0.05
# Define seven outlier detection tools to be compared
classifiers = {
        'Angle-based Outlier Detector (ABOD)': ABOD(contamination=outliers_fraction),
        'Cluster-based Local Outlier Factor (CBLOF)':CBLOF(contamination=outliers_fraction,check_estimator=False, random_state=random_state),
        'Feature Bagging':FeatureBagging(LOF(n_neighbors=35),contamination=outliers_fraction,check_estimator=False,random_state=random_state),
        'Histogram-base Outlier Detection (HBOS)': HBOS(contamination=outliers_fraction),
        'Isolation Forest': IForest(contamination=outliers_fraction,random_state=random_state),
        'K Nearest Neighbors (KNN)': KNN(contamination=outliers_fraction),
        'Average KNN': KNN(method='mean',contamination=outliers_fraction)
}

现在,我们将逐个拟合每个模型的数据,看看每个模型预测异常值的方式有多么不同。

xx , yy = np.meshgrid(np.linspace(0,1 , 200), np.linspace(0, 1, 200))

for i, (clf_name, clf) in enumerate(classifiers.items()):
    clf.fit(X)
    # predict raw anomaly score
    scores_pred = clf.decision_function(X) * -1
        
    # prediction of a datapoint category outlier or inlier
    y_pred = clf.predict(X)
    n_inliers = len(y_pred) - np.count_nonzero(y_pred)
    n_outliers = np.count_nonzero(y_pred == 1)
    plt.figure(figsize=(10, 10))
    
    # copy of dataframe
    dfx = df
    dfx['outlier'] = y_pred.tolist()
    
    # IX1 - inlier feature 1,  IX2 - inlier feature 2
    IX1 =  np.array(dfx['Item_MRP'][dfx['outlier'] == 0]).reshape(-1,1)
    IX2 =  np.array(dfx['Item_Outlet_Sales'][dfx['outlier'] == 0]).reshape(-1,1)
    
    # OX1 - outlier feature 1, OX2 - outlier feature 2
    OX1 =  dfx['Item_MRP'][dfx['outlier'] == 1].values.reshape(-1,1)
    OX2 =  dfx['Item_Outlet_Sales'][dfx['outlier'] == 1].values.reshape(-1,1)
         
    print('OUTLIERS : ',n_outliers,'INLIERS : ',n_inliers, clf_name)
        
    # threshold value to consider a datapoint inlier or outlier
    threshold = stats.scoreatpercentile(scores_pred,100 * outliers_fraction)
        
    # decision function calculates the raw anomaly score for every point
    Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) * -1
    Z = Z.reshape(xx.shape)
          
    # fill blue map colormap from minimum anomaly score to threshold value
    plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), threshold, 7),cmap=plt.cm.Blues_r)
        
    # draw red contour line where anomaly score is equal to thresold
    a = plt.contour(xx, yy, Z, levels=[threshold],linewidths=2, colors='red')
        
    # fill orange contour lines where range of anomaly score is from threshold to maximum anomaly score
    plt.contourf(xx, yy, Z, levels=[threshold, Z.max()],colors='orange')
        
    b = plt.scatter(IX1,IX2, c='white',s=20, edgecolor='k')
    
    c = plt.scatter(OX1,OX2, c='black',s=20, edgecolor='k')
       
    plt.axis('tight')  
    
    # loc=2 is used for the top left corner 
    plt.legend(
        [a.collections[0], b,c],
        ['learned decision function', 'inliers','outliers'],
        prop=matplotlib.font_manager.FontProperties(size=20),
        loc=2)
      
    plt.xlim((0, 1))
    plt.ylim((0, 1))
    plt.title(clf_name)
    plt.show()

OUTPUT

OUTLIERS : 447 INLIERS : 8076 Angle-based Outlier Detector (ABOD)

OUTLIERS :  427 INLIERS :  8096 Cluster-based Local Outlier Factor (CBLOF)

OUTLIERS :  386 INLIERS :  8137 Feature Bagging

OUTLIERS :  501 INLIERS :  8022 Histogram-base Outlier Detection (HBOS)
OUTLIERS :  427 INLIERS :  8096 Isolation Forest

OUTLIERS :  311 INLIERS :  8212 K Nearest Neighbors (KNN)

OUTLIERS :  176 INLIERS :  8347 Average KNN

在上图中,白点是由红线包围的内点,黑点是蓝色区域中的异常值。

End Notes

这对我来说也是一次难以置信的学习经历。 我花了很多时间研究PyOD并用Python实现它。 我鼓励你这样做。 练习在不同的数据集上使用它 - 它是一个非常有用的库!

PyOD已经支持大约20种经典的异常值检测算法,可用于学术和商业项目。 其贡献者计划通过实施与时间序列和地理空间数据配合良好的模型来增强工具箱。

如果您对该文章有任何建议/反馈,请在下面的评论部分发布。 我期待听到您使用PyOD的经历。 快乐学习。

Check out the below awesome courses to learn data science and it’s various aspects:

  • Introduction to Data Science (Certified Course)
  • Python for Data Science
  • Big Mart Sales Prediction using R

你可能感兴趣的:(机器学习,AI程序员,机器视觉)