Python:从列表中删除异常值。这段代码出了什么问题?

时间:2012-09-11 13:21:54

标签: python

以下代码片段来自我的一个函数,它传递了一个数字列表,并且应该从列表中删除异常值(即非常大或非常小的数字)。

代码似乎没有按预期工作,因为输出确认:

EXTREMA_CUTOFF_THRESHOLD=3.0

if list_values:    
    avg_val = sum(list_values)/float(len(list_values))
    print 'DEBUG: BEFORE:', min(list_values), max(list_values), avg_val
    list_values = [x for x in list_values if math.fabs(x - avg_val)/float(avg_val) < EXTREMA_CUTOFF_THRESHOLD]

    list_values_len = len(list_values)
    if (list_values_len > 0) and (min_sample_size > 0) and (list_values_len < min_sample_size):
        print 'DEBUG: Insufficient data for stats calculation for row'
    elif (list_values_len > 0):
        print 'DEBUG: AFTER:', min(list_values), max(list_values), avg_val

输出:

DEBUG: BEFORE: 11.0 302.0 113.897260274
DEBUG: AFTER: 11.0 302.0 113.897260274
DEBUG: BEFORE: 12.5 273.0 108.382352941
DEBUG: AFTER: 12.5 273.0 108.382352941
DEBUG: BEFORE: 2.5 245.5 69.9166666667
DEBUG: AFTER: 2.5 245.5 69.9166666667
DEBUG: BEFORE: 136.5 499.5 363.775
DEBUG: AFTER: 136.5 499.5 363.775
DEBUG: BEFORE: 39.5 422.5 166.035759097
DEBUG: AFTER: 39.5 422.5 166.035759097
DEBUG: BEFORE: 39.5 422.0 152.305007587
DEBUG: AFTER: 39.5 422.0 152.305007587
DEBUG: BEFORE: 20.5 331.0 84.41015625
DEBUG: AFTER: 20.5 331.0 84.41015625
DEBUG: BEFORE: 7.0 267.5 155.810126582
DEBUG: AFTER: 7.0 267.5 155.810126582

为什么极端值没有被滤除?

4 个答案:

答案 0 :(得分:5)

一件事:过滤列表后,您不会重新计算avg_val

另一件事:你和EXTREMA_CUTOFF_THRESHOLD一起玩过吗?也许3.0不会过滤掉测试数据集中的任何内容,但是值较低。

一般性评论:在这种情况下我会使用numpy并使用数据集的标准差(numpy.std(dataarray))来确定异常值(参见@ mgilson对特定方法的评论) )。关于异常检测的一个很好的资源似乎是这篇维基百科文章:http://en.wikipedia.org/wiki/Outlier

答案 1 :(得分:1)

请注意,通过sum / len计算平均值的天真方法会失去数值精度。此外,您可能还想计算标准偏差。

你的阈值方程式

math.fabs(x - avg_val)/float(avg_val) < EXTREMA_CUTOFF_THRESHOLD

可能应该是

math.fabs(x - avg_val)/float(   standard_deviation  ) < EXTREMA_CUTOFF_THRESHOLD

至少如果您计划使用经典的正态分布假设(例如3 sigma异常值),这些假设是根据标准偏差定义的!

您使用的是什么门槛?在您的第一个数据集上,如果您使用3,则很容易看到没有值大于455.58904109600002或小于-227.79452054800001

(请注意,使用标准偏差进行规范化可以解决此问题。不要盲目地降低阈值。)

您也计算错误的长度:list_values_len = len(bid_values)

答案 2 :(得分:1)

您的代码正常运行。只是没有一个极值超过平均值的平均值的3倍,这就是你的算法所暗示的

答案 3 :(得分:1)

您的术语math.fabs(x - avg_val)/float(avg_val)表示“一个数据与平均值相对于平均值的距离”。我认为这没有多大意义。想象一下诞生的那一年,我。即所有数字都在1920年至2010年的范围内。将距离与平均值的绝对值相关联并没有多大意义。

回到原点:考虑一个更合适的规则来找出你想要剥离的元素。这里的其他答案已经提到了。