我有一些列表,其中每个列表包含相似的数字(容差:+/- 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)
但是我对代码不满意,因为我期待更简单的代码。你能否告诉我完成这项任务的更简单方法?
答案 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]
以这种方式一次性完成这个过程:
答案 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]
>>>