高效删除NumPy中的行

2 投票
3 回答
5087 浏览
提问于 2025-04-17 00:28

我有一个很大的numpy数组,里面有很多ID值(我们叫它X):

X:
id   rating
1    88
2    99
3    77
4    66
...

等等。我还有另一个numpy数组,里面是一些“坏ID”——这些ID代表我想从X中删除的行。

B: [2, 3]

所以最后,我想要的是:

X:
id   rating
1    88
4    66

有没有什么简单的方法可以做到这一点,而不需要一个一个地去处理?

3 个回答

0

如果你想彻底删除不好的ID的信息,可以试试这个方法:

x = x[numpy.in1d(x[:,0], bad, invert=True)]

这个方法用的内存比较少,而且速度应该很快。(这里的bad被转换成了一个numpy数组,所以为了让这个方法有效,bad不能是一个集合,具体可以参考这个链接
如果bad的数量非常少,使用下面的方法可能会更快:

from functools import reduce
x = x[~reduce(numpy.logical_or, (x[:,0] == b for b in bad))]

注意:第一行代码在Python3中是必须的。
这个方法也用的内存不多,因为它使用了生成器。

2

重现原作者提到的问题:

X = NP.array('1 88 2 99 3 77 4 66'.split(), dtype=int).reshape(4, 2)
bad_ids = [3,2]
bad_ideas = set(bad_ideas)    # see jterrance comment below this Answer

将Python内置的成员测试功能进行向量化,也就是 X in Y 这种写法。

@NP.vectorize
def filter_bad_ids(id) :
    return id not in bad_ids


>>> X_clean = X[filter_bad_ids(X[:,0])]
>>> X_clean                                # result
   array([[ 1, 88],
          [ 4, 66]])
8

这是我想到的最快的方法:

import numpy

x = numpy.arange(1000000, dtype=numpy.int32).reshape((-1,2))
bad = numpy.arange(0, 1000000, 2000, dtype=numpy.int32)

print x.shape
print bad.shape

cleared = numpy.delete(x, numpy.where(numpy.in1d(x[:,0], bad)), 0)
print cleared.shape

这段代码的输出是:

(500000, 2)
(500,)
(499500, 2)

而且运行速度比 ufunc 快很多。它会使用一些额外的内存,但这是否可以接受取决于你的数组有多大。

解释:

  • numpy.in1d 会返回一个和 x 一样大小的数组,如果某个元素在 bad 数组里,就返回 True,否则返回 False
  • numpy.where 会把这个 True/False 的数组转换成一个整数数组,里面包含了所有 True 的索引位置。
  • 然后,它会把这些索引位置传给 numpy.delete,告诉它沿着第一个轴(0轴)删除对应的元素。

撰写回答