2014-02-24 47 views
0

我有一个像字典的列表中删除异常值:从2D名单

t = [{k: 1, 'a': 22, 'b': 59}, {k: 2, 'a': 21, 'b': 34}, {'k': 3, 'a': 991, 'b': 29}, {'k': 4, 'a': 45, 'b': 11}, {'k': 5, 'a'; 211, 'b': 77}, {'k': 6, 'a': 100, 'b': 1024}] 

如何从它删除异常值,这样我可以有一个是围绕一些有意义的价值为中心的一切或者它没有价值,其太大还是太小?

谢谢。

+1

您必须指定“有意义”是什么。一般来说,所有的数字都是有意义的,除非证明相反 – mgkrebbs

+0

也许你可以定义“方式太大或太小”...... – roippi

+0

一个有意义的值可以是我认为大部分值都以它为中心的东西。一种识别方法是采用列表的平均值,但问题是这是一个2d列表,其中a和b彼此不相关并且是独立变量。并且,在我猜测的同一帧中可以采用太大或太小的方式:就像所有的滤波值不应该偏离那个有意义的值。我猜在这种情况下,它将是一个(n,m )矢量? – user2480542

回答

2

以此为起点,你可以把你的数据变成记录阵列:

import numpy as np 
t = [{'k': 1, 'a': 22, 'b': 59}, {'k': 2, 'a': 21, 'b': 34}, {'k': 3, 'a': 991, 'b': 29}, {'k': 4, 'a': 45, 'b': 11}, {'k': 5, 'a': 211, 'b': 77}, {'k': 6, 'a': 100, 'b': 1024}] 
foo = np.core.records.fromrecords([x.values() for x in t], names=t[0].keys()) 

这使得一些容易分析:

In [34]: foo.a.mean(), foo.a.std() 
Out[34]: (231.66666666666666, 345.81674659018785) 

In [35]: foo.b.mean(), foo.b.std() 
Out[35]: (205.66666666666666, 366.58590019560518) 

也许你可以找一个箱形图离群?

from matplotlib import pyplot 
pyplot.boxplot([foo.a, foo.b]) 
pyplot.show() 

或者,您也可以在数据的第90百分位中找到值:

In [40]: foo.a[foo.a < np.percentile(foo.a, 90)] 
Out[40]: array([ 22, 21, 45, 211, 100]) 

,并选择非离群k值:

outlier_mask = (foo.a < np.percentile(foo.a, 90)) & (foo.b < np.percentile(foo.b, 90)) 
foo.k[outlier_mask] 

当然,如何你决定哪些值是异常值取决于你。

+0

但我如何检索所有不是异常值的k值? – user2480542

+0

看到我更新的答案。 – perimosocordiae

+0

嘿peri,谢谢你的方法。因为百分点的概念几乎是我以前的事情,所以似乎非常有效。让我检查一下它的更多可能性。谢谢。 – user2480542

1

下面的代码找到离平均值最远的点,将其删除,然后再次检查平均值。如果移除该点导致平均值小于给定的容差(通过对旧平均值的百分比变化),则移动被拒绝并返回旧列表。否则,新列表将保留,并且过程继续。

t = [{'a': 22, 'b': 59, 'k': 1}, 
{'a': 21, 'b': 34, 'k': 2}, 
{'a': 991, 'b': 29, 'k': 3}, 
{'a': 45, 'b': 11, 'k': 4}, 
{'a': 211, 'b': 77, 'k': 5}, 
{'a': 100, 'b': 1024, 'k': 6}] 

K = [te['k'] for te in t] 
A = [te['a'] for te in t] 
B = [te['b'] for te in t] 

data = zip(K,A,B) 

def mean(A): 
    return sum(A)/float(len(A)) 

def max_deviation(A): 
    mu = mean(A) 
    dev = [(a, abs(a-mu)) for a in A] 
    dev.sort(key=lambda k: k[1], reverse=True) 
    return dev[0][0] 

def remove_outliers(A, tol=.3): 
    mu = mean(A) 
    A_prime = list(a for a in A if a != max_deviation(A)) 
    mu_prime = mean(A_prime) 
    if abs(mu_prime - mu)/float(mu) > tol: 
     return remove_outliers(A_prime, tol) 
    else: 
     return A 

t_prime = [dict(k=k, a=a, b=b) for k, a, b in data 
      if a in remove_outliers(A) and b in remove_outliers(B)] 

>>> print t_prime 
[{'a': 22, 'b': 59, 'k': 1}, 
{'a': 21, 'b': 34, 'k': 2}, 
{'a': 45, 'b': 11, 'k': 4}] 

编辑:因为它是去除一个值,而不是创建N-1的值的这可能比例更好。这将修改原始的A矢量。如果你不想这样做,那么第一个选项将是你的最佳选择,或者先发送一份副本。

def remove_outliers(A, tol=.3): 
    mu = mean(A) 
    out = max_deviation(A) 
    A.remove(out) 
    mu_prime = mean(A) 
    if abs(mu_prime - mu)/float(mu) > tol: 
     return remove_outliers(A, tol) 
    else: 
     A.append(out) 
     return A 
+0

嘿cdhagmann..this似乎kool。问题是,在处理一些离群数据和数十万行数据时,它会保持更低的价格吗?我希望它会,但让我试试它。非常感谢您的亲切回答。:-) – user2480542

+0

如果您使用了'A.remove(max_deviation(A))',那么您可以帮助扩大规模,如果更改被拒绝,则可以将该值加回。我将添加一个编辑。 – cdhagmann