我最新的数据科学项目涉及预测特定商店中每种产品的销售情况。 有几种方法可以解决这个问题。 但无论我使用哪种型号,我的准确度分数都不会提高。
我花了一些时间检查数据后才发现问题 - 异常值!
这是我们经常忽略的一个错误。诱惑是开始根据您给出的数据建立模型。但这实际上是让自己陷入失败之中。
数据探索没有捷径可走。如果您跳过数据科学项目的这个阶段,构建模型只会让您到目前为止。经过一段时间后,您将达到准确度上限 - 模型的性能不会让步。
数据探索包括许多因素,例如变量识别,处理缺失值,特征工程等。检测和处理异常值也是数据探索阶段的主要因素。输入的质量决定了输出的质量!
PyOD是一个用于检测数据中异常值的库。它提供对20多种不同算法的访问,以检测异常值,并兼容Python 2和3.绝对的宝石!
在本文中,我将带您了解异常值以及如何使用Python中的PyOD检测异常值。
本文假设您具有机器学习算法和Python语言的基本知识。 你可以参考这篇文章 - “机器学习要点”,了解 或刷新这些概念。
异常值是任何数据点,与数据集中的其余观察结果差别很大。 让我们看一些真实的例子来理解异常值检测:
存在异常值的原因有很多。 也许分析师在数据输入中出错,或者机器在测量中引起错误,或者异常值甚至可能是故意的! 有些人不想透露他们的信息,因此在表格中输入虚假信息。
异常值有两种类型:单变量和多变量。 单变量异常值是仅由一个变量中的极值组成的数据点,而多变量异常值是至少两个变量的组合异常分数。 假设您有三个不同的变量 - X,Y,Z。如果您在三维空间中绘制这些变量的图形,它们应该形成一种云。 位于此云之外的所有数据点都将是多变量异常值。
我强烈建议您阅读这本关于数据探索的精彩指南,其中详细介绍了异常值。
异常值可以极大地影响我们的分析和统计建模的结果。 查看下面的图像,可视化出现异常值时模型发生的情况与处理异常值时的情况:
但这里是警告 - 离群值并不总是坏事。 了解这一点非常重要。 简单地从数据中删除异常值而不考虑它们如何影响结果是一种灾难。
“异常值不一定是坏事。 这些只是不遵循相同模式的观察
和其他人一样。 但事实上异常值非常有趣。 例如,如果在生物学中
实验,一只老鼠没有死,而其他一切都是,那么理解为什么会非常有趣。
这可能会带来新的科学发现。 因此,检测异常值非常重要。“
– Pierre Lafaye de Micheaux, Author and Statistician
我们倾向于使用简单的方法,如箱形图,直方图和散点图来检测异常值。 但是,专用异常值检测算法在处理大量数据并需要在较大数据集中执行模式识别的方法中非常有价值。
金融中的欺诈检测和网络安全中的入侵检测等应用需要密集而准确的技术来检测异常值。 你能想象如果你发现一个离群值并且结果是真的那么会有多尴尬吗?
PyOD库可以介入以弥补这一差距。 让我们看看它的全部内容。
许多异常检测包存在于各种编程语言中。 我特别发现这些语言在R中很有用。但是当我切换到Python时,显然缺少异常值检测库。 这怎么可能?!
像PyNomaly这样的现有实现并不是专门为异常值检测而设计的(虽然它仍然值得一试!)。 为填补这一空白,Yue Zhao,Zain Nasrullah和Zheng Li设计并实施了PyOD库。
PyOD是一个可扩展的Python工具包,用于检测多变量数据中的异常值。 它可以在一个详细记录API下访问大约20个离群值检测算法。
PyOD有几个优点,并且有许多有用的功能。 这是我挑选的一堆:
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和其他库。
让我们看看为PyOD提供动力的异常值检测算法。 它很好并且很好地实现了PyOD,但我觉得理解它在底层是如何工作同样重要。 当您在数据集上使用它时,这将为您提供更大的灵活性。
注意:我们将在本节中使用术语外围分数。 这意味着每个模型以某种方式对数据点进行评分而不是使用阈值来确定该点是否是异常值。
足够的谈话 - 让我们看看一些行动。 在本节中,我们将在Python中实现PyOD库。 我将使用两种不同的方法来演示PyOD:
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如何在着名的大市场销售问题上做.
继续从上面的链接下载数据集。 让我们从导入所需的库并加载数据开始:
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
在上图中,白点是由红线包围的内点,黑点是蓝色区域中的异常值。
这对我来说也是一次难以置信的学习经历。 我花了很多时间研究PyOD并用Python实现它。 我鼓励你这样做。 练习在不同的数据集上使用它 - 它是一个非常有用的库!
PyOD已经支持大约20种经典的异常值检测算法,可用于学术和商业项目。 其贡献者计划通过实施与时间序列和地理空间数据配合良好的模型来增强工具箱。
如果您对该文章有任何建议/反馈,请在下面的评论部分发布。 我期待听到您使用PyOD的经历。 快乐学习。
Check out the below awesome courses to learn data science and it’s various aspects: