乐趣区

关于数据分析:异常值检测最佳统计方法实践代码实现⛵

数据集中的异样值,对于数据分布、建模等都有影响。本文解说两大类异样值的检测办法及其 Python 实现:可视化办法(箱线图 & 直方图)、统计办法(z 分数 & 四分位距)。


💡 作者:韩信子 @ShowMeAI
📘 Python3◉技能晋升系列:https://www.showmeai.tech/tutorials/56
📘 数据分析实战系列:https://www.showmeai.tech/tutorials/40
📘 本文地址:https://www.showmeai.tech/article-detail/336
📢 申明:版权所有,转载请分割平台与作者并注明出处
📢 珍藏 ShowMeAI 查看更多精彩内容

💡 异样值 Q&A

异样值 是间隔其余数据值太远的数据点,也被称为 离群点。它可能是天然产生的,也可能是因为测量不精确、拼写错误或系统故障造成的。异样值也可能呈现在歪斜数据中,这些类型的异样值被认为是天然异样值。

理解异样值检测与剖析的基础知识,请查看 ShowMeAI](https://www.showmeai.tech/) 这篇文章:

  • 图解数据分析 | 数据荡涤与预处理

💦 异样值对散布有什么影响?

异样值会影响数据的均值、标准差和四分位数值。如果咱们在去除异样值之前和之后计算这些统计数据,可能会有比拟大的差别。

💦 异样值对机器学习模型有什么影响?

  • 如果认为异样值是天然的,不是因为测量谬误产生的 → 应该将其保留在数据集中,并用『标准化』等数据预处理形式解决。
  • 如果有一个蕴含大量异样值的大型数据集 → 应该将其保留,不会显著影响后果。
  • 如果确定异样值是由测量误差造成的 → 应该将它们从数据集中删除。

去除异样值会带来数据集规模的减小,而且模型的适用性也会限度在输出值的度量范畴内,抛弃天然异样值也可能导致模型不精确。

💡 基于可视化的异样值检测

异样值不容易被『肉眼』检测到,但咱们有一些可视化工具能够帮忙实现这项工作。最常见的是箱线图和直方图。咱们这里用 🏆保险数据 来做一个解说:

🏆 实战数据集下载(百度网盘):公✦众✦号『ShowMeAI 钻研核心』回复『实战 』,或者点击 这里 获取本文 [[29] 基于统计办法的异样值检测代码实战](https://www.showmeai.tech/art…)『insurance 数据集

ShowMeAI 官网 GitHub:https://github.com/ShowMeAI-Hub

咱们首先导入必要的库并加载数据集。

import numpy as np
import pandas as pd
import seaborn as sns
import statistics#Load dataset:
df = pd.read_csv('insurance.csv')
df

咱们对变量『年龄』、『体重指数』和『费用』进行异样值检测剖析。

第一种办法是应用箱线图 / Box-Plots 来绘制数据分布:

# age, bmi 和 expenses 的箱线图绘图
sns.boxplot(y="age", data=df)
sns.boxplot(y="bmi", data=df)
sns.boxplot(y="expenses", data=df)

通过查看箱线图,咱们能够看到变量 age 没有异样值,变量 bmi 在下限中有一些异样值,而变量 expense 在下限中有一系列异样值(表明存在偏态散布)。

为了查看偏态散布,咱们再应用直方图绘图:

# age, bmi 和 expenses 的直方图
sns.histplot(df, x="age", kde=True)
sns.histplot(df, x="bmi", kde=True)
sns.histplot(df, x="expenses", kde=True)

通过直方图,咱们能够看到变量『age』是近似均匀分布,『bmi』靠近正态分布,而『expense/ 费用』则呈偏态散布。

对于年龄,咱们无需做异样值剔除;对于 bmi,咱们将剔除高于 47 的值;对于费用,咱们将剔除高于 50000 的值。

#bmi 和 expenses 的异样值解决
df.drop(df[df['bmi'] >= 47].index, inplace = True)
df.drop(df[df['expenses'] >= 50000].index, inplace = True)

当初,如果咱们再次查看箱线图和直方图:

💡 基于统计办法的异样值检测

检测异样值有两种次要的统计办法:应用 z 分数和应用四分位距。

💦 应用 z 分数检测异样值

Z 分数是一种数学变换,它依据每个观测值与平均值的间隔对其进行分类。z-score 的计算公示为:

咱们定义异样检测规范:如果 z-score 小于 - 3 或 z-score 大于 3。

咱们将从新加载数据集,因为咱们在后面的示例中对其进行了更改,加载后的数据上咱们会把变量转换为 z 分数:

# 从新加载数据
df = pd.read_csv('insurance.csv')

# 为 age 计算均值和标准差
mean_age = statistics.mean(df['age'])
stdev_age = statistics.stdev(df['age'])

# 计算 z 值
age_z_score = (df['age']-mean_age)/stdev_age

# 增加 z 后果到原 dataframe
df['age_z_score'] = age_z_score.tolist()

当初咱们将查看高于 3SD 或低于 -3SD 的值:

# 检测小于 -3SD 的值:
df.sort_values(by=['age_z_score'], ascending=True)

咱们能够看到 -3SD 以下没有值。咱们当初将查看 3SD 以上的值:

# 检测 +3SD 以上的值:
df.sort_values(by=['age_z_score'], ascending=False)

咱们能够看到没有高于 3SD 的值。变量年龄没有异样值。

当初咱们将对变量 bmi 执行雷同的操作:

# 为 bmi 计算均值和标准差
mean_bmi = statistics.mean(df['bmi'])
stdev_bmi = statistics.stdev(df['bmi'])

# 为 bmi 计算 z -score
bmi_z_score = (df['bmi']-mean_bmi)/stdev_bmi

# 增加到原始 dataframe
df['bmi_z_score'] = bmi_z_score.tolist()

# 查看低于 -3SD 的值
df.sort_values(by=['bmi_z_score'], ascending=True)

# 查看大于 3SD 的值
df.sort_values(by=['bmi_z_score'], ascending=False)

这次咱们会发现一些高于 3SD 的值:

咱们对它进行剔除:

# 异样值解决
df.drop(df[df[‘bmi_z_score’] >= 3].index, inplace = True)

咱们将对『expense/ 费用』利用雷同的技术:

# 为 expenses 计算均值和标准差
mean_expenses = statistics.mean(df['expenses'])
stdev_expenses = statistics.stdev(df['expenses'])

# 计算 z -score
expenses_z_score = (df['expenses']-mean_expenses)/stdev_expenses

# 增加到原始 dataframe
df['expenses_z_score'] = expenses_z_score.tolist()

# 查看低于 -3SD 的值
df.sort_values(by=['expenses_z_score'], ascending=True)

# 查看高于 3SD 的值
df.sort_values(by=['expenses_z_score'], ascending=False)

# 异样值解决
df.drop(df[df[‘expenses_z_score’] >= 3].index, inplace = True)

如果咱们再次查看箱线图和直方图,咱们将取得:

💦 应用四分位距检测异样值

四分位间距将数据分为四个局部,从低到高排序,如下图所示,每个局部蕴含雷同数量的样本。第一个四分位数(Q1)是边界中数据点的值。这同样实用于 Q2 和 Q3。四分位距(IQR)是两个两头局部的数据点(代表 50% 的数据)。四分位距蕴含高于 Q1 和低于 Q3 的所有数据点。如果该点高于 Q3 + (1.5 x IQR),则存在较高的异样值,如果 Q1 – (1.5 x IQR),则存在较低的异样值。

代码实现如下:

# 从新加载数据
df = pd.read_csv('insurance.csv')

# 计算高低四分位数地位
q75_age, q25_age = np.percentile(df['age'], [75 ,25])
iqr_age = q75_age - q25_age
iqr_age

# 计算高低边界以用于异样检测
age_h_bound = q75_age+(1.5*iqr_age)
age_l_bound = q25_age-(1.5*iqr_age)
print(age_h_bound)
print(age_l_bound)

咱们计算失去上边界 87 和下边界 -9:

# 排序
df.sort_values(by=['age'], ascending=True)
# 排序
df.sort_values(by=['age'], ascending=False)

咱们看到没有异样值。

咱们对变量 bmi 执行雷同的操作:

# 计算高低四分位数地位
q75_bmi, q25_bmi = np.percentile(df['bmi'], [75 ,25])
iqr_bmi = q75_bmi - q25_bmi
iqr_bmi

# 计算高低边界以用于异样检测
bmi_h_bound = q75_bmi+(1.5*iqr_bmi)
bmi_l_bound = q25_bmi-(1.5*iqr_bmi)
print(bmi_h_bound)
print(bmi_l_bound)

# 排序
df.sort_values(by=['bmi'], ascending=True)
df.sort_values(by=['bmi'], ascending=False)

# 剔除异样值
df.drop(df[df['bmi'] >= 47.3].index, inplace = True)
df.drop(df[df['bmi'] <= 13.7].index, inplace = True)

咱们只须要对可变费用做同样的事件,咱们将取得以下箱线图和直方图:

参考资料

  • 📘 图解数据分析 | 数据荡涤与预处理:https://www.showmeai.tech/article-detail/138
退出移动版