如何从数字列表中删除高度差异化的元素

时间:2014-03-01 12:24:14

标签: python

我有一些列表,其中每个列表包含相似的数字(容差:+/- 10%)。但有时候列表中也包含噪音:与其他“普通”元素有很大差异的元素。

以下是一些示例:

a = [100, 102, 99, 225, 105]
b = [150, 142, 24, 153, 147, 315, 149]
c = [34, 33, 31, 80, 32, 30]

我想要的是一种自动消除这些噪音的简单方法。从第一个列表中,应删除225。从第二个列表中,应删除24315。从上一个列表中,应删除80。目前,我的代码是:

import math

def foo(numbers):
    numbers_filtered = []
    for i, n in enumerate(numbers):
        n_upper = n + (n * 0.1)
        n_lower = n - (n * 0.1)
        similar = 0
        for j, m in enumerate(numbers):
            if i == j:
                continue
            if m >= n_lower and m <= n_upper:
                similar += 1
        if similar >= math.ceil(len(numbers) / 2.0):
            numbers_filtered.append(n)

    print('%s -> %s' % (numbers, numbers_filtered))

a = [100, 102, 99, 225, 105]
b = [150, 142, 24, 153, 147, 315, 149]
c = [34, 33, 31, 80, 32, 30]
foo(a)
foo(b)
foo(c)

但是我对代码不满意,因为我期待更简单的代码。你能否告诉我完成这项任务的更简单方法?

5 个答案:

答案 0 :(得分:1)

一种简单的方法是使用标准偏差:

avg = sum(numbers) / len(numbers)
diff = [ (i - avg) ** 2 for i in numbers]
stddev = math.sqrt(sum(diff) / len(numbers))

# filter out outliers
result = []
for n in numbers:
    distance = abs(n - avg)
    if distance < stddev * FACTOR:
        result.append( n )

定义正确的FACTOR可能是一项挑战,因此不会丢弃太多的数字。您可以添加其他外部循环以检查已删除的数量,并相应地更新FACTOR。这将允许像“保持至少50%的数字”这样的逻辑。

答案 1 :(得分:0)

我不知道python,但这是概念。我将采用您使用的阵列:

  

a = [100, 102, 99, 225, 105]

以这种方式一次性完成这个过程:

  1. 100,102-diff 2(2/100 = .02即2%),两者都好
  2. 102,99-diff 3(3/102 = .03,即3%),99是好的
  3. 99,225 - 差异126(126/99 = 1.27,即127%),太高,掉落
  4. 99再次,105 - 差异6(6/99 = .06即6%),105可以

答案 2 :(得分:0)

我的评论代码: 这只保留了与平均值相差一定数量标准差的元素。

>>> def mean(array, function=None):
        function = function or (lambda x: x)
        return sum(map(function, array))/len(array)

>>> def standard_deviation(array, function=None):
        function = function or (lambda x: x)
        array_mean = mean(array, function=function)
        differences = [(i-array_mean)**2 for i in array]
        return math.sqrt(mean(differences))

>>> def foo(array, function=None):
        function = function or (lambda x: x)
        deviation = standard_deviation(array, function=function)
        array_mean = mean(array, function=function)
        return [i for i in array if abs(function(i)-array_mean) <= deviation*TOLERANCE]

>>> foo([100, 102, 99, 225, 105])
[100, 102, 99, 105]
>>> foo([150, 142, 24, 153, 147, 315, 149])
[150, 142, 153, 147, 149]
>>> foo([34, 33, 31, 80, 32, 30])
[34, 33, 31, 32, 30]

将容差设置为您想要的任何值。对于你想要的结果,我使用了1.5。

如果元素是“自定义对象的属性”,这也将起作用。你可以这样做:

>>> foo(my_array, lambda x: x.some_attribute_we_want_to_compare)

甚至更好:

>>> from operator import attrgetter
>>> foo(my_array, attrgetter("some_attribute_we_want_to_compare")

答案 3 :(得分:0)

这可以通过成对访问列表元素来解决。我编写了以下代码并验证输出符合您的期望:

a = [100, 102, 99, 225, 105]
comp = -1
for x, y in zip(a,a[1:]):
    if comp != -1:
        x=comp
    if x-y > 10 or x-y < -10:
        a.remove(y)
        comp = x
    else:
        comp = x
print a

输出:

[100, 102, 99, 105]
[150, 142, 153, 147, 149]
[34, 33, 31, 32, 30]

答案 4 :(得分:0)

比较您的示例的中位数工作但如果有批次的噪音可能会有问题 - 在这种情况下调整容差可能会有所帮助。

a = [100, 102, 99, 225, 105]
b = [150, 142, 24, 153, 147, 315, 149]
c = [34, 33, 31, 80, 32, 30]

tolerance = 0.1

for example in (a, b, c):
    example.sort()
    median = float(example[len(example) / 2])
    print example, median, 
    print [n for n in example if 1 - tolerance <= median / n <= 1 + tolerance]

>>> 
[99, 100, 102, 105, 225] 102 [99, 100, 102, 105]
[24, 142, 147, 149, 150, 153, 315] 149 [142, 147, 149, 150, 153]
[30, 31, 32, 33, 34, 80] 33 [30, 31, 32, 33, 34]
>>>