机器学习 异常值检测与处理

异常值是指不属于某一特定群体的数据点。它是一个与其他数值大不相同的异常观测值,与良好构成的数据组相背离。在机器学习建模准备数据集时,检测出所有的异常值,并且要么移除它们、要么分析它们来了解它们最初存在的原因是非常重要的。

一、异常值检测

波士顿房价数据集

卡内基梅隆大学,StatLib库,1978年,涵盖了麻省波士顿的506个不同郊区的房屋数据。
404条训练数据集,102条测试数据集。
每条数据14个字段,包含13个属性,和一个房价的平均值。

在这里插入图片描述

1.1 简单统计

在实际工作中,表中会有很多脏数据,对特征值进行简单统计之后,结合业务及自己的经验,分析某些特征是否存在异常值和异常值是什么。例如有一个特征是人的身高,出现了一个大于5m的数值,根据常识肯定是异常值;特征性别,假设出现了男女之外的情况,也是异常值等等。

1.2 3σ原则检测

在统计学中,如果一个数据分布式近似正态分布,那么大约68%的数据值在平均值的前后一个标准差范围内,大约95%的数据值在平均值的前后两个标准差范围内,大约99.7%的数据值在前后三个标准差的范围内。在3σ原则下,异常值如超过3倍标准差,那么可以将其视为异常值。

数值分布在数据中的占比
(μ-σ,μ+σ)0.6827
(μ-2σ,μ+2σ)0.9545
(μ-3σ,μ+3σ)0.9973

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

在这里插入图片描述
红色箭头所指的数据在正负3σ之外,因此是异常值。

import numpy as np
import pandas as pd
from sklearn import datasets


def three_sigma(Ser1):
    '''
    3σ法则识别异常值函数
    Ser1:表示传入DataFrame的某一列。
    '''
    rule = (Ser1.mean()-3*Ser1.std()>Ser1) | (Ser1.mean()+3*Ser1.std()< Ser1)
    index = np.arange(Ser1.shape[0])[rule]
    outrange = Ser1.iloc[index]
    return outrange


if __name__ == '__main__':
    boston_data = datasets.load_boston()
    df = pd.DataFrame(boston_data.data, columns=boston_data.feature_names)
    # 对犯罪率这里列进行3σ法则识别,把不遵守正太分布的数据挑选出来
    data = three_sigma(df['CRIM']).head()
    print(data)

输出结果如下:

[5 rows x 13 columns]
380    88.9762
398    38.3518
404    41.5292
405    67.9208
410    51.1358
Name: CRIM, dtype: float64

1.3 箱线图检测

和3σ原则相比,箱线图依据实际数据绘制,真实、直观地表现出了数据分布的本来面貌,且没有对数据作任何限制性要求(3σ原则要求数据服从正态分布或近似服从正态分布),其判断异常值的标准以四分位数和四分位距为基础。四分位数给出了数据分布的中心、散布和形状的某种指示,具有一定的鲁棒性,即25%的数据可以变得任意远而不会很大地扰动四分位数,所以异常值通常不能对这个标准施加影响。由于箱线图识别异常值的结果比较客观,因此在识别异常值方面具有一定的优越性。

箱型图提供了识别异常值的一个标准,即异常值通常被定义为小于QL-1.5IQR或大于QU+1.5IQR的值。

  • QL:下四分位数Q1,表示全部观察值中有四分之一的数据取值比它小,数据的1/4位置;
  • QU:上四分位数Q3,表示全部观察值中有四分之一的数据取值比它大,数据的3/4位置;
  • IQR:四分位数间距,是上四分位数QU与下四分位数QL之差(Q3-Q1),其间包含了全部观察值的一半。
  • 下须:下须是非异常值范围内的最小值,等于QL-1.5IQR
  • 上须:上须是非异常范围内的最大值,等于Q3+1.5IQ3

在这里插入图片描述

画图展示

import seaborn as sns
ax = sns.boxplot(y=df["CRIM"])

箱线图如下:
在这里插入图片描述
从箱线图可以看出大于8左右的都为异常值

使用代码检测

def box_plot(Ser):
    '''
    箱线图法检测异常值函数
    Ser:进行异常值分析的DataFrame的某一列
    '''
    Low = Ser.quantile(0.25)-1.5*(Ser.quantile(0.75)-Ser.quantile(0.25))
    Up = Ser.quantile(0.75)+1.5*(Ser.quantile(0.75)-Ser.quantile(0.25))
    index = (Ser< Low) | (Ser>Up)
    Outlier = Ser.loc[index]
    return(Outlier)


if __name__ == '__main__':
    boston_data = datasets.load_boston()
    df = pd.DataFrame(boston_data.data, columns=boston_data.feature_names)
    data = box_plot(df['CRIM']).head()
    print(data)

识别结果如下:

367    13.5222
371     9.2323
373    11.1081
374    18.4982
375    19.6091
Name: CRIM, dtype: float64

从代码打印的5个结果来看,均符合箱线图展示结果

1.4 DBScan密度聚类

DBScan是一种被用于基于密度的对于一维或多维数据的异常检测方法,DBScan有三个重要概念:

  • 核心点:为了理解核心点,我们需要访问一些用于定义DBScan工作的超参数。第一个超参数是最小值样本(min_samples)。这只是形成集聚的核心点的最小数量。第二重要的超参数eps,它是两个被视为在同一个簇中的样本之间的最大距离。
  • 边界点:是与核心点在同一集群的点,但是要离集群中心远得多。
  • 其他的点:称为噪声点,那些数据点不属于任何集群。它们可能是异常点,可能是非异常点,需要进一步调查。现在让我们看看代码。

在这里插入图片描述

import numpy as np
from sklearn.cluster import DBSCAN

# 设置随机数种子
np.random.seed(1)
random_data = np.random.randn(50000, 2) * 20 + 20

outlier_detection = DBSCAN(min_samples=2, eps=3)
clusters = outlier_detection.fit_predict(random_data)
print(list(clusters).count(-1))

# 94

上述代码的输出值是94。这是噪声点的总数。SKLearn将噪声点标记为(-1)。这种方法的缺陷就是维数越高,精度越低。你还需要做出一些假设,比如估计eps的正确值,而这可能是有挑战性的。

二、异常值处理

检测到了异常值,我们需要对其进行一定的处理。而一般异常值的处理方法可大致分为以下几种:

  • 删除含有异常值的记录:直接将含有异常值的记录删除;
  • 视为缺失值:将异常值视为缺失值类别,利用缺失值处理的方法进行处理;
  • 平均值修正:可用前后两个观测值的平均值修正该异常值;
  • 不处理:直接在具有异常值的数据集上进行数据挖掘,比如数值特征离散化操作可以减少异常值的影响;

是否要删除异常值可根据实际情况考虑。因为一些模型对异常值不很敏感,即使有异常值也不影响模型效果,但是一些模型比如逻辑回归LR对异常值很敏感,如果不进行处理,可能会出现过拟合等非常差的效果。

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值