python异常值检测的方法_【Python实战】单变量异常值检测

【Python实战】单变量异常值检测

异常值检测是数据预处理阶段重要的环节,这篇文章介绍下对于单变量异常值检测的常用方法,通过Python代码实现。

一、什么是异常值

异常值是在数据集中与其他观察值有很大差距的数据点,它的存在,会对随后的计算结果产生不适当的影响,因此检测异常值并加以适当的处理是十分必要的。

二、异常值的处理

异常值并不都是坏的,了解这一点非常重要。只是简单地从数据中删除异常值,而不考虑它们如何影响结果的话,可能会导致灾难。

“异常值不一定是坏事。这些只是与其他模式不一致的观察。但事实上异常值非常有趣。例如,如果在生物实验中,某只老鼠没有死亡而其他老鼠都死了,去了解为什么将会非常有趣。这可能会带来新的科学发现。因此,检测异常值非常重要。” —— Pierre Lafaye de Micheaux,统计师

对于异常值,一般有如下几种处理:

删除含有异常值的记录(是否删除根据实际情况考虑)

将异常值视为缺失值,利用缺失值的处理方法进行处理

平均值修正(前后两个观测值的平均值)

不处理(直接在具有异常值的数据集上进行挖掘)

三、异常值的类型

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

举个例子:做客户分析,发现客户的年平均收入是80万美元。但是,有两个客户的年收入是4美元和420万美元。这两个客户的年收入明显不同于其他人,那这两个观察结果将被视为异常值,并且是单变量异常值,当我们看到单变量的分布时,可以找到这些异常值。

再举个例子:身高和体重之间的关系。我们对“身高”和“体重”有单变量和双变量分布,如下图所示。

loading.gif

看箱线图(box plot后面会介绍)没有任何异常值,再看散点图(scatter plot),有两个值在一个特定的身高和体重的平均值以下。可见多变量异常值是n维空间中的异常值,必须通过多维度的分布才能体现出来。

如果对异常值不太了解,可以阅读这篇《数据探索指南》,上述部分解释也是从中摘录的。

下面,我主要记录下单变量异常值检测的Python实现。

四、常用异常检测方法

原则上模拟数据集需要样本量足够大,这里仅是演示算法,所以就手动写了有限的样本。

异常值的测量标准有很多,比较常见的是描述性统计法、三西格玛法(3σ法)、箱线图等:

1. 描述性统计

基于常识或经验,假定我们认为大于10的数值是不符合常理的。

下面用Python代码实现用描述性统计求异常值:

# -*- coding: utf-8 -*-

data = [2.78, 1.79, 4.73, 3.81, 2.78, 1.80, 4.81, 2.79, 1.78, 3.32, 10.8, 100.0]

threshold = 10

# 定义描述性统计识别异常值函数

def descriptive_statistics(data):

return list(filter(lambda x: x > threshold, data))

outliers = descriptive_statistics(data)

print('异常值共有:{0}个,分别是:{1}'.format(len(outliers), outliers))

# 输出:异常值共有:2个,分别是:[10.8, 100.0]

2. 三西格玛(3σ)

当数据服从正态分布时,99%的数值应该位于距离均值3个标准差之内的距离,P(|x−μ|>3σ)≤0.003,当数值超出这个距离,可以认为它是异常值。

正态分布状况下,数值分布表:

数值分布

在数据中的占比

(μ-σ,μ+σ)

0.6827

(μ-2σ,μ+2σ)

0.9545

(μ-3σ,μ+3σ)

0.9973

注:在正态分布中σ代表标准差,μ代表均值,x=μ为图形的对称轴

下面用Python代码实现用三西格玛求异常值:

# -*- coding: utf-8 -*-

import pandas as pd

import numpy as np

data = [2.78, 1.79, 4.73, 3.81, 2.78, 1.80, 4.81, 2.79, 1.78, 3.32, 10.8, 100.0]

# 定义3σ法则识别异常值函数

def three_sigma(data_series):

rule = (data_series.mean() - 3 * data_series.std() > data_series) | (data_series.mean() + 3 * data_series.std() < data_series)

index = np.arange(data_series.shape[0])[rule]

outliers = data_series.iloc[index]

return outliers.tolist()

data_series = pd.Series(data)

outliers = three_sigma(data_series)

print('异常值共有:{0}个,分别是:{1}'.format(len(outliers), outliers))

# 输出:异常值共有:1个,分别是:[100.0]

3. 箱线图(box plot)

和3σ原则相比,箱线图依据实际数据绘制,真实、直观地表现出了数据分布的本来面貌,且没有对数据作任何限制性要求(3σ原则要求数据服从正态分布或近似服从正态分布)。

其判断异常值的标准以四分位数和四分位距为基础。四分位数给出了数据分布的中心、散布和形状的某种指示,具有一定的鲁棒性,即25%的数据可以变得任意远而不会很大地扰动四分位数,所以异常值通常不能对这个标准施加影响。鉴于此,箱线图识别异常值的结果比较客观,因此在识别异常值方面具有一定的优越性。

箱线图提供了识别异常值的一个标准,即:

上界 = Q3 + 1.5IQR

下界 = Q1 - 1.5IQR

小于下界或大于上界的值即为异常值。

其中,

Q3称为上四分位数(75%),表示全部观察值中只有四分之一的数据取值比它大;

Q1称为下四分位数(25%),表示全部观察值中只有四分之一的数据取值比它小;

IQR称为四分位数差,这里就是 Q3-Q1;

1.5其实是个参数λ,这个参数通常取1.5(类似于正态分布中的μ±λ)

文字描述可能比较绕,下面用图片来解释下。

loading.gif

第一四分位数 (Q1),又称“较小四分位数”,等于该样本中所有数值由小到大排列后第25%的数字。

第二四分位数 (Q2),又称“中位数”,等于该样本中所有数值由小到大排列后第50%的数字。

第三四分位数 (Q3),又称“较大四分位数”,等于该样本中所有数值由小到大排列后第75%的数字。

Q3与Q1的差距又称四分位距(InterQuartile Range,IQR)。

下面用Python代码实现用箱线图求异常值:

# -*- coding: utf-8 -*-

import pandas as pd

data = [2.78, 1.79, 4.73, 3.81, 2.78, 1.80, 4.81, 2.79, 1.78, 3.32, 10.8, 100.0]

# 定义箱线图识别异常值函数

def box_plot(data_series):

q_abnormal_low = data_series.quantile(0.25) - 1.5 * (data_series.quantile(0.75) - data_series.quantile(0.25))

q_abnormal_up = data_series.quantile(0.75) + 1.5 * (data_series.quantile(0.75) - data_series.quantile(0.25))

index = (data_series < q_abnormal_low) | (data_series > q_abnormal_up)

outliers = data_series.loc[index]

return outliers.tolist()

sorted_data = sorted(data)

data_series = pd.Series(sorted_data)

outliers = box_plot(data_series)

print('异常值共有:{0}个,分别是:{1}'.format(len(outliers), outliers))

# 输出:异常值共有:2个,分别是:[10.8, 100.0]

五、总结

以上是最基础的几种单变量异常值检测方法,没有最好的,只有对当前数据场景最合适的。

后期如果涉及机器学习的数据预处理,我会继续学习和研究多变量异常值的检测,相信会有更有意思的一些算法等着我去学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值