删除每列中的异常值(以及相应的行)

时间:2014-08-22 12:49:42

标签: python numpy scipy

我的Numpy数组包含10列和大约200万行。

现在我需要分别分析每个列,找到异常值;并从数组中删除整个相应的行。

所以我开始分析第0列;在10,20,100排找到异常值;并删除这些行。 接下来,我将开始分析现在修剪过的数组中的第1列;并应用相同的过程。

当然我可以想到一个正常的手动过程来执行此操作(遍历每一列,查找异常值的索引,删除行,继续到其他列),但我总是发现Numpy包含一些快速的巧妙技巧完成这些统计任务。

如果你能详细说明方法的运行时成本;甚至更好。

我不仅限于NumPy库,如果SciPy有用,那么使用它就没有问题。

谢谢!

2 个答案:

答案 0 :(得分:4)

两种非常直接的方法,第二种方法更为复杂:

arr = np.random.randn(2e6, 10)

def remove_outliers(arr, k):
    mu, sigma = np.mean(arr, axis=0), np.std(arr, axis=0, ddof=1)
    return arr[np.all(np.abs((arr - mu) / sigma) < k, axis=1)]

def remove_outliers_bis(arr, k):
    mask = np.ones((arr.shape[0],), dtype=np.bool)
    mu, sigma = np.mean(arr, axis=0), np.std(arr, axis=0, ddof=1)
    for j in range(arr.shape[1]):
        col = arr[:, j]
        mask[mask] &= np.abs((col[mask] - mu[j]) / sigma[j]) < k
    return arr[mask]

性能取决于你有多少异常值:

In [38]: %timeit remove_outliers(arr, 1)
1 loops, best of 3: 1.13 s per loop

In [39]: %timeit remove_outliers_bis(arr, 1)
1 loops, best of 3: 983 ms per loop

In [40]: %timeit remove_outliers(arr, 2)
1 loops, best of 3: 1.21 s per loop

In [41]: %timeit remove_outliers_bis(arr, 2)
1 loops, best of 3: 1.51 s per loop

当然:

In [42]: np.allclose(remove_outliers(arr, 1), remove_outliers_bis(arr, 1))
Out[42]: True

In [43]: np.allclose(remove_outliers(arr, 2), remove_outliers_bis(arr, 2))
Out[43]: True

我会说第二种方法的复杂性并不能证明其潜在的加速,但是YMMV ......

答案 1 :(得分:0)

效果最佳的解决方案取决于查找异常值,删除行以及异常值频率的相对成本。

如果你的异常频率不是很高,我会这样做:

  • 创建一个离群值的布尔表(原始表中每个元素的一个元素)
  • 沿轴(每行的总和)求和表
  • 创建一个新表,其中只有异常值为0的行

逐个删除行需要花费大量时间,如果查找异常值并不是非常昂贵,那么由于可能在同一行中找到多个异常值而导致的额外工作并不重要。

作为代码,这将是:

outliers = find_outliers(data)
data_without_outliers = data[outliers.sum(axis=1) == 0]

其中find_outliers创建一个离群值状态的布尔表(即True,如果原始数组data中的对应元素是异常值。)

我的猜测是性能取决于您的离群检测算法。如果你可以简单和矢量化,那么这很快。