精华内容
下载资源
问答
  • 异常值检测

    2021-02-01 21:05:51
    利用高斯分布这一有利工具来进行异常值检测

    背景

    无论在自然界还是人类社会生产生活中,都会存在那么一小撮不随大流的人或事物,这一小撮往往对整体影响很大,如何准确高效的把这一小部分的对象甄别出来俨然称为一个很具挑战性的工作。本文将带你利用高斯分布这一有利工具来进行异常值检测。

    高斯分布

    高斯分布又名正态分布,是用来描述随机变量的分布规律,这里先给出一维高斯分布的定义

    如果随机变量X服从一个数学期望值为μ\mu、方差为σ2\sigma^2的概率分布,且概率密度函数为

    f(x)=12πσe(xμ)22σ2f(x) = \frac{1}{\sqrt {2\pi} \sigma} e^{-\frac{(x-\mu)^2}{2\sigma^2}}

    则称X服从高斯分布,记为

    XN(μσ2)X \thicksim N(μ,σ^2)

    其中数学期望值μ决定其位置,方差σ2\sigma^2决定其波幅。特别的,当$μ = 0, \sigma^2 = 1 $时的高斯分布是标准正态分布(一般不称标准高斯分布)。

    下面不加证明的给出二维独立高斯分布的概率密度函数

    f(x,y)=12πσ1σ2e[(xμ1)22σ12+(xμ2)22σ22]f(x,y ) = \frac{1}{{2\pi} \sigma_1 \sigma_2} e^{-[\frac{(x-\mu_1)^2}{2\sigma_1^2}+\frac{(x-\mu_2)^2}{2\sigma_2^2}]}

    有意思的是在三维空间中这个函数的图像投影到平面上是一系列同心椭圆,他们的中心都在(u1,u2)(u_1, u_2)

    Figure_1  二维标准正态分布

    高斯分布是最常见的一种概率分布,科学家认为现实生活中很多现象符合高斯分布,且认为偏离高斯分布的3个标准差之外的是极小可能发生的情况,即异常情况,于是可以利用高斯分布来看数据是否是正常的还是异常的。

    实践

    本次以吴恩达第八次作业为例,动手实验异常值检测,包括原始数据的可视化,二维高斯分布的概率密度函数及其参数估计,最佳阈值的选定和异常值的筛选及异常数据的可视化。

    数据可视化

    我们一直强调如果原始数据能够可视化,那么毫不犹豫先可视化,可视乎之后能够非常直观的看到数据的大致分布情况,异常值大概是哪些。

    import math
    import numpy as np
    import matplotlib
    import scipy.io as scio
    import matplotlib.pyplot as plt 
    
    data = scio.loadmat(r"D:\项目\机器学习\吴恩达机器学习课件\CourseraML\ex8\data\ex8data1.mat") #读取mat数据
    X  = data["X"] #特征
    Xval = data['Xval']  #验证集
    yval = data["yval"] #验证集对应的标签
    
    def dataVisual(myX): #数据可视化
        plt.figure(figsize = (6, 4)) #新建画布
        plt.scatter(myX[:,0], myX[:,1], c="b", marker="x", linewidths=0.5) #散点图
        plt.xlabel("latency (ms)") #横坐标标签
        plt.ylabel("throughput (mb/s)") #纵坐标标签
        plt.show()
    

    Figure_2 原数据散点图

    从原数据的散点图可以看到大概有那么一些点的确跟大伙不一样,离群性严重,将其圈起来便是

    Figure_3  圈出异常值

    现在就是要设计一套模式把刚才手动圈起来的点自动识别出来。

    二维高斯分布

    要自动识别异常点,这时候多维高斯分布能够为我所用,利用样本数据来估计高斯分布的参数(μ,σ2\mu, \sigma^2),然后再计算各样本的高斯概率值,并且还可以把高斯分布概率密度函数的投影画出来。

    def estimateGaussian(myX): #高斯分布的参数估计,即均值和方差(标准差)
        m = len(myX) #样本数
        n = myX.shape[1] #特征数
        mu = myX.mean(axis = 0) #每个特征的均值
        sigma = myX.std(axis =0, ddof = 0) #每个特征的方差,ddof=1表示无偏估计,ddof=0表示无偏估计
        return mu, sigma
    
    def gaussianDistribution(myx, myy, mymu1, mymu2, mysigma1, mysigma2): #二维高斯概率密度函数
        gaussian = (1/(2*math.pi*mysigma1*mysigma2))*math.e**(-(myx-mymu1)**2/(2*mysigma1**2) - (myy-mymu2)**2/(2*mysigma2**2) )
        return gaussian
    
    def plotContour(myX): #等值线
        mu, sigma = estimateGaussian(myX) #高斯分布的估计参数
        x = np.linspace(np.min(myX[:,0])-1, np.max(myX[:,0])+1, 100) #经度
        y = np.linspace(np.min(myX[:,0])-1, np.max(myX[:,1])+1, 100) #纬度
        xx, yy  = np.meshgrid(x, y) #制作经纬网格线
        zz = gaussianDistribution(xx, yy, mu[0], mu[1], sigma[0], sigma[1]) #网格点上的高斯概率值
        #print(xx.shape, yy.shape, zz.shape)
        cont_levels = [10 ** h for h in range(-20, 1, 3)] #指定的级别绘制轮廓线, 必须按递增顺序排列
        plt.contour(xx, yy, zz, cont_levels, linewidths=0.7) #等值线
        plt.scatter(myX[:,0], myX[:,1], c="b", marker="x", linewidths=0.5) #原散点图
        plt.show()
    

    Figure_4 等值线

    模型挑选

    虽然多维高斯分布可以识别出异常值,但是怎么具体确定哪些是异常值,哪些是正常值,并且能够评估这种异常值自动识别的效果如何?针对第一个问题,可以设定一个阈值,小于阈值的断定为异常值,反之为正常值;针对第二个问题,可以设定一个损失函数,比如f1得分,利用验证集f1的表现情况来确定最终的阈值。

    def computeF1(y_pred, y_true): #计算f1-score,即损失函数
        tp, fp, tn, fn = 0, 0, 0, 0  #初始化
        for i in range(len(y_pred)):
            if y_pred[i]==y_true[i]:
                if y_true[i]==1:
                     tp +=1
                else:
                     tn +=1
            else:
                if y_true[i] ==1:
                    fn +=1
                else:
                    fp+=1
        precision = tp/(tp+fp) if tp+fp else 0 #精确率
        recall = tp/(tp+fn)  if tp+fn else 0 #召回率
        f1 = 2*precision*recall/(precision+recall)  if precision+recall else 0 #f1得分
        return f1
    
    def selectThreshold(yval, pval): #通过验证集来选择最佳的阈值
        epsilons = np.linspace(np.min(pval), np.max(pval), 1000) 
        best_f1, best_epsilon = 0, 0 #初始化
        for e in epsilons: #从极小概率值到极大概率值
            y_pred = (pval < e).astype(float) #如果小于阈值则认为是异常值
            f1 = computeF1(y_pred, yval) #计算f1值
            if f1 > best_f1: #如果f1值有所提升
                best_f1 = f1 #更新f1
                best_epsilon = e #更新epsilon
        return best_f1, best_epsilon
    

    挑选异常值和可视化

    知道哪些是异常值,哪些是非异常值,就能够把这些异常值样本挑出来,并打上标签。

    def abnormlyVisual(myX, myepsilon, mymu, mysigma): #先挑出异常值并可视化标记出来
        guassian = gaussianDistribution(myX[:,0], myX[:,1], mu[0], mu[1], sigma[0], sigma[1]) #计算高斯概率分布函数值
        abnorm_points = np.array([myX[i] for i in range(len(guassian)) if guassian[i]< myepsilon]) #跳出异常值点
        plt.figure() #新建画布
        plt.scatter(myX[:,0], myX[:,1], c="b", marker="x", linewidths=0.5) #原散点图
        plt.scatter(abnorm_points[:,0], abnorm_points[:,1], facecolor="w", edgecolors="r", marker="o") #异常值标注
        plt.show()
    

    Figure_5 异常值可视化

    大致经过这样几个步骤,就完成了异常值检测及其可视化工作了。

    优缺点分析

    (1) 理论通俗,操作简单

    异常值检测主要利用了高斯分布理论来界定哪些是异常值,哪些是非异常值,理论比较通俗,操作起来也比较简单。

    (2) 不具备通用性

    虽然很多现象符合高斯分布,是从人类的经验中总结出来的规律,然而规律始终是规律,不能严谨证明,不能当成公理来使,现实生活中肯定还有非高斯分布的现象,这时候利用高斯分布来区分异常值和非异常值是缺乏科学性的,不符合真实情况。

    应用场景

    (1) 数据预处理

    在数据预处理的时候需要对异常值进行剔除,常规做法是利用箱线图的上下四分位点的1.5倍内距来框定,而箱线图的理论基础也是高斯分布,与异常值识别的理论基础是一致,所以在数据预处理的时候可以利用今天所讲的异常值处理办法;

    (2) 风险控制

    做风控模型的朋友经常要和“黑”样本,“白”样本打交道,现实生活中的"黑"样本占比是极少的,这时候可以把"黑"样本当作异常值来识别和处理;

    参考文献

    1,https://blog.csdn.net/cowry5/article/details/80541524
    2,https://blog.csdn.net/weixin_44027820/article/details/104616231

    在这里插入图片描述

    展开全文
  • 【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]

    五、总结

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

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

    展开全文
  • 【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]

    五、总结

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

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

    展开全文
  • 作者: eavea 发表日期: 2020年04月14日 分类: 后端技术标签: Python , 数据处理阅读次数: 6,076评论数: 0 条【Python实战】单变量异常值检测异常值检测是数据预处理阶段重要的环节,这篇文章介绍下对于单变量异常值...

    作者: eavea 发表日期: 2020年04月14日 分类: 后端技术

    标签: Python , 数据处理

    阅读次数: 6,076

    评论数: 0 条

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

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

    一、什么是异常值

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

    二、异常值的处理

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

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

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

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

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

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

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

    三、异常值的类型

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

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

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

    height_weight_outliers.png

    看箱线图(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(类似于正态分布中的μ±λ)

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

    box_plot.png

    第一四分位数 (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]

    五、总结

    展开全文
  • PyOD - 用于异常值检测的Python工具包(也称为异常检测)
  • matlab开发-异常值检测和移动。在非线性时间序列中用适当的局部值检测和替换异常值。
  • 原标题:Python数据分析基础: 异常值检测和处理1 什么是异常值?在机器学习中,异常检测和处理是一个比较小的分支,或者说,是机器学习的一个副产物,因为在一般的预测问题中,模型通常是对整体样本数据结构的一种...
  • 带R降价的异常值检测
  • 经典的异常值检测方法根据异常值的研究角度和方向,异常值检测方法大体可分为基于统计的方法、基于距离的方法、基于偏离的方法和基于密度的方法。1. 经典异常值检测方法分析 1.1.基于统计的检测方法 从 20 世纪 80 ...
  • 异常值检测模型

    2019-12-24 16:18:04
    异常值检测 异常值检测之LOF 判断输入值是否为数值型数据,在输入数据类型相同的情况下判断俩点之间的距离 语法点: 一、isinstance(object, classinfo) 参数 object – 实例对象。 classinfo – 可以是直接或间接...
  • 异常值检验发现和剔除异常观测值的统计检验方法...异常值检验方法有很多,针对不同数据特点,时间序列数据和截面数据的检测方法不完全相同,其时常要考虑到数据特性,本文主要介绍几种常用的异常值检测方法。首先,...
  • MATLAB源码集锦-RPCA异常值检测代码
  • 异常值检测算法

    万次阅读 多人点赞 2017-05-13 14:50:17
    闲话:最近总是特别嗜睡,不知为何床对我的引力总是让我死死的赖在上面,大概是懒癌又犯了....要改。 异常值分析是检验数据是否有录入错误以及含有...常用的异常值检测方法主要有: 1. 简单统计量分析: 先对变量做一个
  • IQR(InterQuartile Range)检测常用于一维数据的异常值检测,首先计算数据的下四分位数Q1(25%分位数)、中位数Q2(50%)分位数、上四分位数Q3(75%分位数),再计算 IQR = Q3 - Q1,最好通过k来调整范围,得到异常...
  • 一、概况两大异常novelty detection这些训练数据没有被异常值所污染,我们有兴趣在新的观测中发现异常。outlier detection训练数据中包含异常值,和我们需要合适的训练数据中心模式忽略的越轨的意见。机器学习(无...
  • 机器学习——异常值检测

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,899
精华内容 1,159
关键字:

异常值检测