离群值是一个数据项/对象,它明显偏离其余的(所谓的正常)对象。它们可能由测量或执行错误引起。离群点检测的分析被称为离群点挖掘。检测离群值的方法有很多,删除过程与从pandas的数据框中删除数据项相同。
在这里,pandas数据框架用于更现实的方法,因为现实世界的项目需要检测数据分析步骤中出现的离群值,相同的方法可以用于列表和序列类型的对象。
# Importing
import sklearn
from sklearn.datasets import load_diabetes
import pandas as pd
import matplotlib.pyplot as plt
# Load the dataset
diabetics = load_diabetes()
# Create the dataframe
column_name = diabetics.feature_names
df_diabetics = pd.DataFrame(diabetics.data)
df_diabetics.columns = column_name
df_diabetics.head()
离群值可以使用可视化、在数据集上实现数学公式或使用统计方法来检测。下文将讨论所有这些问题。
使用箱形图可视化离群值
它只需要一个简单的框和须就可以有效地捕获数据摘要。箱形图使用第25次、第50次和第75次采样总结了样本数据。人们可以通过查看数据集的箱形图来了解数据集(四分位数,中位数和离群值)。
# Box Plot
import seaborn as sns
sns.boxplot(df_diabetics['bmi'])
在上图中,可以清楚地看到,高于10的值是离群值。
# Position of the Outlier
import numpy as np
print(np.where(df_diabetics['bmi']>0.12))
输出
(array([ 32, 145, 256, 262, 366, 367, 405]),)
使用散点图可视化离群值
当您有成对的数值数据,并且因变量对每个阅读自变量有多个值时,或者当尝试确定两个变量之间的关系时,使用该方法。在利用散点图的过程中,也可以将其用于离群值检测。
要绘制散点图,需要两个变量以某种方式彼此相关。因此,这里使用的是“每个城镇的非零售业务面积比例”和“每10,000美元的全额财产税税率”,其列名分别为“INDUS”和“TAX”。
# Scatter plot
fig, ax = plt.subplots(figsize=(6, 4))
ax.scatter(df_diabetics['bmi'], df_diabetics['bp'])
# x-axis label
ax.set_xlabel('(body mass index of people)')
# y-axis label
ax.set_ylabel('(bp of the people )')
plt.show()
查看图表可以总结出大多数数据点都在图表的左下角,但很少有点正好相反,即图表的右上角。右上角的那些点可以被视为离群值。
使用近似可以说所有那些x>20和y>600的数据点都是离群值。下面的代码可以获取满足这些条件的所有点的精确位置。
BMI和BP列合并的离群值
在这里,NumPy的np.where()函数用于在DataFrame df_diabetics中查找条件(df_diabetics[‘bmi’] > 0.12) & (df_diabetics[‘bp’] < 0.8) 为真的位置(索引)。该条件检查bmi大于0.12且bp小于0.8的离群值。输出提供DataFrame中离群值位置的行和列索引。
# Position of the Outlier
print(np.where((df_diabetics['bmi'] > 0.12) & (df_diabetics['bp'] < 0.8)))
输出
(array([ 32, 145, 256, 262, 366, 367, 405]),)
Z-score
Z-score也称为标准分数。该值/分数有助于理解数据点距离平均值有多远。并且在设置阈值之后,可以利用数据点的z得分值来定义离群值。
Zscore = (data_point -mean) / std. deviation
在本例中,我们使用SciPy stats模块中的zscore函数计算DataFrame df_diabetics中“age”列的Z分数。生成的数组z包含“age”列中每个数据点的绝对Z分数,指示每个值与平均值的标准差。
# Z score
from scipy import stats
import numpy as np
z = np.abs(stats.zscore(df_diabetics['age']))
print(z)
输出
[0.80050009 0.03956713 1.79330681 1.87244107 0.11317236 1.94881082
0.9560041 1.33508832 0.87686984 1.49059233 2.02518057 0.57139085
0.34228161 0.11317236 0.95323959 1.1087436 0.11593688 1.48782782
0.80326461 0.57415536 1.03237385 1.79607132 1.79607132 0.95323959
1.33785284 1.41422259 2.25428981 0.49778562 1.10597908 1.41145807
1.26148309 0.49778562 0.72413034 0.6477606 0.34228161 1.02960933
0.26591186 0.19230663 0.03956713 0.03956713 0.11317236 2.10155031
1.26148309 0.41865135 0.95323959 0.57139085 1.18511334 1.64333183
1.41145807 0.87963435 0.72413034 1.25871858 1.1087436 0.19230663
1.03237385 0.87963435 0.87963435 0.57415536 0.87686984 1.33508832
1.49059233 0.87963435 0.57415536 0.72689486 1.41145807 0.9560041
0.19230663 0.87686984 0.80050009 0.34228161 0.03956713 0.03956713
1.33508832 0.26591186 0.26591186 0.19230663 0.65052511 2.02518057
0.11317236 2.17792006 1.48782782 0.26591186 0.34504612 0.80326461
0.03680262 0.95323959 1.49059233 0.95323959 1.1087436 0.9560041
0.26591186 0.95323959 0.42141587 1.03237385 1.64333183 1.49059233
1.18234883 0.57415536 0.03680262 0.03956713 0.34228161 0.34228161]
上面的输出只是部分数据的快照;列表的实际长度(z)是506,即行数。它打印列的每个数据项的z得分值
现在,为了定义离群值,选择通常为3.0的阈值。由于99.7%的数据点位于+/- 3标准差之间(使用高斯分布方法)。
Z值大于2的情况下
在这个例子中,我们设置了一个阈值2,然后使用NumPy的np.where()来标识Z分数数组z中绝对Z分数大于指定阈值(2)的位置(索引)。它根据Z分数标准在“年龄”列中打印离群值的位置。
threshold = 2
# Position of the outlier
print(np.where(z > 2))
输出
(array([ 10, 26, 41, 77, 79, 106, 131, 204, 223, 226, 242, 311, 321,344, 374, 402]),)
IQR(四分位数间距)
四分位数间距(IQR)是研究领域中最常用和最可信的离群值发现方法。
IQR = Quartile3 - Quartile1
语法: numpy.percentile(arr, n, axis=None, out=None)
主要参数:
arr:输入数组。 n:百分位数值。
在本例中,我们计算DataFrame df_diabetics中“bmi”列的四分位距(IQR)。它首先使用中点法计算第一四分位数(Q1)和第三四分位数(Q3),然后计算IQR作为Q3和Q1之间的差值,提供“bmi”列中中间50%数据的分布度量。
# IQR
Q1 = np.percentile(df_diabetics['bmi'], 25, method='midpoint')
Q3 = np.percentile(df_diabetics['bmi'], 75, method='midpoint')
IQR = Q3 - Q1
print(IQR)
输出
0.06520763046978838
为了定义离群值基础值定义为高于和低于数据集的正常范围,即上限和下限,定义上限和下限(考虑1.5*IQR值):
upper = Q3 +1.5*IQR
lower = Q1 – 1.5*IQR
在上述公式中,根据统计学,采用IQR的0.5比例放大(new_IQR = IQR + 0.5*IQR),以考虑高斯分布中2.7标准差之间的所有数据。
# Above Upper bound
upper = Q3+1.5*IQR
upper_array = np.array(df_diabetics['bmi'] >= upper)
print("Upper Bound:", upper)
print(upper_array.sum())
# Below Lower bound
lower = Q1-1.5*IQR
lower_array = np.array(df_diabetics['bmi'] <= lower)
print("Lower Bound:", lower)
print(lower_array.sum())
输出
Upper Bound: 0.12879000811776306
3
Lower Bound: -0.13204051376139045
0
为了移除离群值,必须遵循使用其在数据集中的确切位置从数据集中移除条目的相同过程,因为在检测离群值的所有上述方法中,最终结果是根据所使用的方法满足离群值定义的所有那些数据项的列表。
dataframe.drop(row index,inplace=True)
上面的语法可以用来从数据集中删除一行,给定要删除的row_indexes。Inplace =True用于告诉Python在原始数据集中进行所需的更改。row_index只能是一个值或值列表或NumPy数组,但必须是一维的。
例:
df_diabetics.drop(lists[0],inplace = True)
在这个例子中,我们使用四分位距(IQR)方法来检测和删除糖尿病数据集的“bmi”列中的离群值。它基于IQR计算上限和下限,使用布尔数组识别离群值索引,然后从DataFrame中删除相应的行,从而生成排除离群值的新DataFrame。打印DataFrame的前后形状以进行比较。
# Importing
import sklearn
from sklearn.datasets import load_diabetes
import pandas as pd
# Load the dataset
diabetes = load_diabetes()
# Create the dataframe
column_name = diabetes.feature_names
df_diabetes = pd.DataFrame(diabetes.data)
df_diabetes .columns = column_name
df_diabetes .head()
print("Old Shape: ", df_diabetes.shape)
''' Detection '''
# IQR
# Calculate the upper and lower limits
Q1 = df_diabetes['bmi'].quantile(0.25)
Q3 = df_diabetes['bmi'].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5*IQR
upper = Q3 + 1.5*IQR
# Create arrays of Boolean values indicating the outlier rows
upper_array = np.where(df_diabetes['bmi'] >= upper)[0]
lower_array = np.where(df_diabetes['bmi'] <= lower)[0]
# Removing the outliers
df_diabetes.drop(index=upper_array, inplace=True)
df_diabetes.drop(index=lower_array, inplace=True)
# Print the new shape of the DataFrame
print("New Shape: ", df_diabetes.shape)
输出
Old Shape: (442, 10)
New Shape: (439, 10)