在Python中检测和删除异常值
在一个数据集中,离群点是指一个与数据集其他部分异常不同的项目。然而,这个定义给了数据分析员足够的空间来决定异常值的阈值。
我们的离群点是由于测量错误、执行错误、抽样问题、错误的数据输入,甚至是自然变化造成的。去除异常值是很重要的,因为它们的存在会增加误差,引入偏见,并对统计模型产生重大影响。
在本教程中,我们将讨论从数据集中检测和移除异常值的方法。我们将把我们的技术应用于著名的波士顿住房数据集,作为scikit-learn库的一部分来演示。
这篇文章的结构是这样的:我们将探讨检测异常值的方法,然后讨论如何使用该技术来移除异常值。
如果你想学习这个教程,你可以在你的浏览器中使用谷歌Colab来完成。这就像打开一个新的笔记本和写代码一样简单。
下面是使用谷歌Colab的分步指南。
设置环境和加载数据集
我们首先要导入一些我们将要使用的库。
import sklearn
from sklearn.datasets import load_boston
import pandas as pd
import matplotlib.pyplot as plt
然后我们可以加载波士顿住房数据集。
bh_dataset = load_boston()
该数据集包含一个feature_names
属性,这是一个包含数据集中所有特征名称的数组。data
属性包含所有的数据。
我们将把这两者分开,然后结合起来,创建一个Pandas数据框。
columns = bh_dataset.feature_names
df_boston = pd.DataFrame(bh_dataset.data)
df_boston.columns = columns
df_boston
现在包含了整个数据集。Pandas允许我们用简洁明了的方式来获得数据集的预览,使用 方法。.head()
如下图所示,调用该函数将显示数据集的预览(也如下图所示)。
df_boston.head()
输出:
在Python中实现数据集的可视化
生成一个箱形图来可视化数据集
箱形图,也被称为盒须图,是一种简单有效的可视化数据的方法,对于寻找异常值特别有帮助。在python中,我们可以使用seaborn库来生成我们的数据集的箱形图。
import seaborn as sns
sns.boxplot(df_boston['DIS'])
上述代码的图:
用'DIS'
对数据集进行索引意味着将DIS
列传入box plot函数。箱形图是在一个维度上生成的。
因此,它只需要一个变量作为输入。该变量可以被改变以生成不同的箱形图。
在上面的图中,我们可以看到,高于10的值是离群值。现在我们将把它作为这个数据集的离群值的标准。
我们可以使用np.where
,在数据集中选择符合这一标准的条目,如下例所示。
import numpy as np
DIS_subset = df_boston['DIS']
print(np.where(DIS_subset > 10))
输出:
这些是包含由上述标准定义的离群值的数据点的数组索引。在文章的最后,我们将向你展示如何使用这些索引从你的数据集中删除离群值。
生成一个散点图来可视化数据集
当我们有跨越单一维度的数据时,可以使用箱形图。然而,如果我们有成对的数据或者我们正在分析的关系涉及两个变量,我们可以使用散点图。
Python允许我们使用Matplotlib来生成散点图。下面是一个打印散点图的代码例子。
fig, axes = plt.subplots(figsize = (18,10))
axes.scatter(df_boston['INDUS'], df_boston['TAX'])
axes.set_xlabel('Non-retail business acres per town')
axes.set_ylabel('Tax Rate')
plt.show()
输出:
得到一个眼球的估计,我们一般可以说,在X轴上,大于20的值看起来像离群值,在Y轴上,大于500的值看起来像离群值。我们可以用这个作为我们去除离群值的标准。
我们将使用之前的numpy
函数来检测符合这个标准的指数。
print(np.where((df_boston['INDUS']>20) & (df_boston['TAX']>500)))
输出:
用Python检测离群值的数学方法
计算Z分数以检测Python中的离群值
Z分数(也称为标准分)是一个统计量,用来衡量一个数据点离平均值有多少标准差。Z分数越大,说明该数据点离平均值越远。
这很重要,因为在正态分布的数据集中,大多数数据点都在平均值附近。一个具有较大Z分数的数据点离大多数数据点较远,很可能是一个离群点。
我们可以使用Scipy的工具来生成Z-score。再一次,我们将选择数据集的一个特定列来应用这个方法。
from scipy import stats
z = stats.zscore(df_boston['DIS'])
z_abs = np.abs(z)
上述代码中的第一行只是导入了库。第二行使用scipy.zscore
方法来计算所选数据集中每个数据点的Z-score。
第三行有一个numpy
函数,将所有的值转换为正值。这有助于我们应用一个简单的过滤器。
打印数组会让我们看到类似这样的东西:
这个图片不包括所有的点,但是你可以通过打印z_abs
。
我们现在必须决定哪些点算作离群点的标准。在处理正态分布时,高于平均值三个标准差的数据点被视为离群点。
这是因为在正态分布中,99.7%的点都在平均值的3个标准差之内。这意味着所有Z-score大于3的点都应该被删除。
再一次,我们将使用np.where
函数来寻找我们的离群指数。了解更多关于np.where
函数的信息。
print(np.where(z_abs > 3))
输出:
在Python中计算四分位数间范围以检测离群值
这是我们要讨论的最后一种方法。这种方法在研究中非常常用,通过去除离群值来清理数据。
四分位数间范围(IQR)是数据的第三四分位数和第一四分位数之间的差。我们把Q1
定义为第一个四分位数,这意味着25%的数据位于最小值和Q1
之间。
我们将Q3
定义为数据的第三个四分位数,这意味着75%的数据位于数据集的最小值和Q3
之间。
有了这些定义,我们就可以定义我们的上界和下界。任何低于下限和高于上限的数据点都将被视为离群点。
Lower bound = Q1 - (1.5 * IQR)
Upper bound = Q3 + (1.5 * IQR)
1.5可能看起来很随意,但它有数学上的意义。如果你对其详细的数学知识感兴趣,请看这篇文章
你需要知道,这大致相当于找到离平均值至少3个标准差的数据(如果我们的数据是正态分布)。在实践中,这种方法是非常有效的。
在Python中,我们可以使用NumPy函数percentile()
,找到Q1
和Q3
,然后找到IQR。
Q1 = np.percentile(df_boston['DIS'], 25, interpolation = 'midpoint')
Q3 = np.percentile(df_boston['DIS'], 75, interpolation = 'midpoint')
IQR = Q3 - Q1
在我们的数据集中,我们打印IQR,得到如下结果:
现在我们将定义我们的上界和下界,如下所示:
upper_bound = df_boston['DIS'] >= (Q3+1.5*IQR)
lower_bound = df_boston['DIS'] <= (Q1-1.5*IQR)
再一次,我们可以用np.where
,得到符合标准的点的指数。
print(np.where(upper_bound))
print(np.where(lower_bound))
输出:
在Python中从数据框架中移除离群值
我们将使用dataframe.drop
函数来删除离群点。点击这里了解更多关于该函数的信息。
为此,我们必须向该函数传递一个包含离群点索引的列表。我们可以这样做:
upper_points = np.where(upper_bound)
df_boston.drop(upper_points[0], inplace=True)
为了验证这些点是否已经被丢弃,我们可以打印我们的数据形状,看看剩余的条目数。
print(df_boston.shape)
df_boston.drop(upper_points[0], inplace=True)
print(df_boston.shape)
输出:
恭喜你!我们已经成功地删除了异常点!这证实了我们已经成功地剔除了我们的离群点。你可以使用我们上面采用的方法传递任何索引列表,并将它们传递给drop函数。