0

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

正如输出证实的那样,代码似乎没有按预期工作:

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

4 回答 4

5

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

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

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

于 2012-09-11T13:25:14.800 回答
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)

于 2012-09-11T13:33:06.440 回答
1

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

于 2012-09-11T13:34:21.277 回答
1

您的术语math.fabs(x - avg_val)/float(avg_val)的意思是“一个数据与平均值的距离相对于平均值”。我认为这没有多大意义。想象一组出生年份,即所有在 1920..2010 范围内的数字。将距离与平均值的绝对值联系起来没有多大意义。

所以回到第一条:考虑一个更体面的规则来找出你想要剥离的元素。这里的其他答案已经提到了这一点。

于 2012-09-11T13:34:23.753 回答