从列表中排除exception值是否有一个粗糙的内build值?

是否有一个像下面这样的内容? 也就是说,取一个列表d并返回一个列表filtered_d ,根据d某些假设的分布点,删除任何外部元素。

 import numpy as np def reject_outliers(data): m = 2 u = np.mean(data) s = np.std(data) filtered = [e for e in data if (u - 2 * s < e < u + 2 * s)] return filtered >>> d = [2,4,5,1,6,5,40] >>> filtered_d = reject_outliers(d) >>> print filtered_d [2,4,5,1,6,5] 

我说'类似',因为函数可能允许变化的分布(泊松,高斯等)和不同的分布内的exception阈值(如我在这里使用的m )。

这个方法几乎和你的一样,只是更多的numpyst(也只在numpy数组上工作):

 def reject_outliers(data, m=2): return data[abs(data - np.mean(data)) < m * np.std(data)] 

处理exception值时重要的是应该尽量使用估计值。 分布的均值将偏离exception值,但是例如中值会less得多。

build立在eumiro的答案:

 def reject_outliers(data, m = 2.): d = np.abs(data - np.median(data)) mdev = np.median(d) s = d/mdev if mdev else 0. return data[s<m] 

在这里,我已经用平均值和平均值的绝对距离替代了平均值和标准差。 然后,我用(再次)中间值对距离进行缩放,以使m处于合理的相对尺度。

在本杰明的基础上,使用pandas.Series , 用IQR代替MAD :

 def reject_outliers(sr, iq_range=0.5): pcnt = (1 - iq_range) / 2 qlow, median, qhigh = sr.dropna().quantile([pcnt, 0.50, 1-pcnt]) iqr = qhigh - qlow return sr[ (sr - median).abs() <= iqr] 

例如,如果将iq_range=0.6设置iq_range=0.6 ,则四分位距的百分位数将变为: 0.20 <--> 0.80 ,因此将包含更多的exception值。

Benjamin Bannier的答案在距离中位数距离的中位数为0时产生一个传递,所以我发现这个修改后的版本对于下例中给出的情况更有帮助。

 def reject_outliers_2(data, m = 2.): d = np.abs(data - np.median(data)) mdev = np.median(d) s = d/(mdev if mdev else 1.) return data[s<m] 

例:

 data_points = np.array([10, 10, 10, 17, 10, 10]) print(reject_outliers(data_points)) print(reject_outliers_2(data_points)) 

得到:

 [[10, 10, 10, 17, 10, 10]] # 17 is not filtered [10, 10, 10, 10, 10] # 17 is filtered (it's distance, 7, is greater than m) 

另一种方法是对标准偏差进行稳健估计(假设高斯统计量)。 查看在线计算器,我发现90%的百分点对应于1.2815σ,95%是1.645σ( http://vassarstats.net/tabs.html?#z

举一个简单的例子:

 import numpy as np # Create some random numbers x = np.random.normal(5, 2, 1000) # Calculate the statistics print("Mean= ", np.mean(x)) print("Median= ", np.median(x)) print("Max/Min=", x.max(), " ", x.min()) print("StdDev=", np.std(x)) print("90th Percentile", np.percentile(x, 90)) # Add a few large points x[10] += 1000 x[20] += 2000 x[30] += 1500 # Recalculate the statistics print() print("Mean= ", np.mean(x)) print("Median= ", np.median(x)) print("Max/Min=", x.max(), " ", x.min()) print("StdDev=", np.std(x)) print("90th Percentile", np.percentile(x, 90)) # Measure the percentile intervals and then estimate Standard Deviation of the distribution, both from median to the 90th percentile and from the 10th to 90th percentile p90 = np.percentile(x, 90) p10 = np.percentile(x, 10) p50 = np.median(x) # p50 to p90 is 1.2815 sigma rSig = (p90-p50)/1.2815 print("Robust Sigma=", rSig) rSig = (p90-p10)/(2*1.2815) print("Robust Sigma=", rSig) 

我得到的输出是:

 Mean= 4.99760520022 Median= 4.95395274981 Max/Min= 11.1226494654 -2.15388472011 Sigma= 1.976629928 90th Percentile 7.52065379649 Mean= 9.64760520022 Median= 4.95667658782 Max/Min= 2205.43861943 -2.15388472011 Sigma= 88.6263902244 90th Percentile 7.60646688694 Robust Sigma= 2.06772555531 Robust Sigma= 1.99878292462 

这接近2的预期值。

如果我们想删除高于/低于5个标准差的点(1000点,我们预期1个值> 3个标准差):

 y = x[abs(x - p50) < rSig*5] # Print the statistics again print("Mean= ", np.mean(y)) print("Median= ", np.median(y)) print("Max/Min=", y.max(), " ", y.min()) print("StdDev=", np.std(y)) 

这使:

 Mean= 4.99755359935 Median= 4.95213030447 Max/Min= 11.1226494654 -2.15388472011 StdDev= 1.97692712883 

我不知道哪种方法更有效率/强大