以下代码片段来自我的一个函数,它传递了一个数字列表,并且应该从列表中删除异常值(即非常大或非常小的数字)。
代码似乎没有按预期工作,因为输出确认:
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
为什么极端值没有被滤除?
答案 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年的范围内。将距离与平均值的绝对值相关联并没有多大意义。
回到原点:考虑一个更合适的规则来找出你想要剥离的元素。这里的其他答案已经提到了。