如何从数字列表中移除高度差异化的元素
我有一些列表,每个列表里包含相似的数字(允许的误差是正负10%)。不过,有时候这些列表里也会有一些噪音:就是那些和其他“正常”元素差别很大的数字。
这里有一些例子:
a = [100, 102, 99, 225, 105]
b = [150, 142, 24, 153, 147, 315, 149]
c = [34, 33, 31, 80, 32, 30]
我想要一个简单的方法,自动去掉这些噪音。在第一个列表中,225
应该被去掉。在第二个列表中,24
和 315
应该被去掉。在最后一个列表中,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]
然后我会一次性处理这个数组,步骤如下:
- 先看100和102,差值是2(2/100=0.02,也就是2%),这两个都没问题。
- 接着是102和99,差值是3(3/102=0.03,也就是3%),99也没问题。
- 然后是99和225,差值是126(126/99=1.27,也就是127%),这个差值太大了,直接舍弃225。
- 最后再看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%的数字”的逻辑。