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

3 投票
5 回答
530 浏览
提问于 2025-04-17 20:25

我有一些列表,每个列表里包含相似的数字(允许的误差是正负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

我对Python不太了解,但我可以给你讲讲这个概念。我会用你提到的数组:

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

然后我会一次性处理这个数组,步骤如下:

  1. 先看100和102,差值是2(2/100=0.02,也就是2%),这两个都没问题。
  2. 接着是102和99,差值是3(3/102=0.03,也就是3%),99也没问题。
  3. 然后是99和225,差值是126(126/99=1.27,也就是127%),这个差值太大了,直接舍弃225。
  4. 最后再看99和105,差值是6(6/99=0.06,也就是6%),105也没问题。
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]
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%的数字”的逻辑。

撰写回答