删除每列的离群值及其对应的行
我的Numpy数组有10列,大约有200万行。
现在我需要分别分析每一列,找出异常值,并删除整个对应的行。
所以我会先分析第0列;找到第10行、第20行和第100行的异常值;然后删除这些行。
接下来,我会在现在已经去掉一些行的数组中分析第1列,并用同样的方法处理。
当然,我可以想到一个普通的手动方法来完成这个过程(逐列遍历,找出异常值的索引,删除行,然后继续分析下一列),但我发现Numpy里有一些快速的小技巧可以用来完成这样的统计任务。
如果你能多说一点这个方法的运行时间成本,那就更好了。
我并不局限于使用NumPy,如果SciPy有什么有用的工具,我也可以使用。
谢谢!
2 个回答
0
最有效的解决方案取决于找出异常值的成本、删除一行的成本,以及异常值出现的频率。
如果你的异常值出现得不太频繁,我建议你可以这样做:
- 创建一个布尔值表,标记哪些是异常值(原始表中的每个元素对应一个布尔值)
- 对这个表进行求和,计算每一行的总和
- 创建一个新表,只保留那些异常值总和为0的行
逐行删除数据会花费很多时间,如果找异常值的过程不太复杂,那么因为同一行可能有多个异常值而增加的工作量就不算太重要。
用代码表示的话,大概是这样的:
outliers = find_outliers(data)
data_without_outliers = data[outliers.sum(axis=1) == 0]
这里的 find_outliers
函数会创建一个布尔值表,标记每个元素是否是异常值(也就是说,如果原始数组 data
中的对应元素是异常值,就标记为 True
)。
我猜性能的好坏还和你用的异常值检测算法有关。如果你能让它简单且高效,那么速度会很快。
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
我觉得第二种方法的复杂性并不值得为了可能的速度提升去使用,但每个人的情况可能不同……