9

我正在使用 numpy.delete 从 while 循环内的数组中删除元素。仅当数组不为空时,此 while 循环才有效。此代码工作正常,但当数组包含超过 1e6 个元素时,速度会大大降低。这是一个例子:

while(array.shape[0] > 0):
     ix = where((array >= x) & (array <= y))[0]
     array = delete(array,ix,None)

我试图让这段代码高效,但我找不到加速 while 循环的好方法。我认为这里的瓶颈是必须涉及某种副本的删除。我已经尝试使用屏蔽数组以避免复制,但我不擅长 python 并且屏蔽数组并不那么容易搜索。有没有一种快速的方法来使用删除或替换它,以便上面的循环可以处理 7e6 元素而无需花费 24 小时?

谢谢

4

3 回答 3

9

因此,您可以通过以下方式显着提高代码的性能:

  • 消除循环;和

  • 避免删除操作(这会导致原始数组的副本)

NumPy 1.7 引入了一个比原来更容易使用的新掩码;它的性能也更好,因为它是NumPy 核心数组对象的一部分。我认为这可能对您有用,因为使用它可以避免昂贵的删除操作

换句话说,不要删除不需要的数组元素,只需将它们屏蔽即可。这已在其他答案中提出,但我建议使用新面具

要使用 NA,只需导入 NA

>>> from numpy import NA as NA

然后对于给定的数组,将 maskna 标志设置为True

>>> A.flags.maskna = True

或者,大多数数组构造函数(从 1.7 开始)都有参数 maskna,您可以将其设置为True

>>> A[3,3] = NA

array([[7, 5, 4, 8, 4],
       [2, 4, 3, 7, 3],
       [3, 1, 3, 2, 1],
       [8, 2, 0, NA, 7],
       [0, 7, 2, 5, 5],
       [5, 4, 2, 7, 4],
       [1, 2, 9, 2, 3],
       [7, 5, 1, 2, 9]])

>>> A.sum(axis=0)
array([33, 30, 24, NA, 36])

通常这不是您想要的——即,您仍然希望将 NA 视为 0 的列的总和:

要获得该行为,请为 skipma 参数传入True (大多数 NumPy 数组构造函数在 NumPy 1.7 中都有此参数):

>>> A.sum(axis=0, skipna=True)
array([33, 30, 24, 33, 36])

总之,为了加快你的代码,消除循环并使用新的掩码:

>>> A[(A<=3)&(A<=6)] = NA

>>> A
array([[8, 8, 4, NA, NA],
       [7, 9, NA, NA, 8],
       [NA, 6, 9, 5, NA],
       [9, 4, 6, 6, 5],
       [NA, 6, 8, NA, NA],
       [8, 5, 7, 7, NA],
       [NA, 4, 5, 9, 9],
       [NA, 8, NA, 5, 9]])

NA 占位符——在这种情况下——表现得像 0,我相信这是你想要的:

>>> A.sum(axis=0, skipna=True)
array([32, 50, 39, 32, 31])
于 2012-05-14T20:25:38.060 回答
3

如果我错了,请纠正我,但我认为你可以这样做:

mask=np.where((array >= x) & (array <= y),True,False)
array=array[mask]

放弃整个循环?

此外,在我的解释器中,array >= x & array <= y会产生异常。你可能的意思是: (array >= x) & (array <= y)

于 2012-05-14T19:43:55.040 回答
1

根据 numpy.delete 的文档,该函数返回输入数组的副本,其中删除了指定的元素。所以你复制的数组越大,函数就越慢。

http://docs.scipy.org/doc/numpy/reference/generated/numpy.delete.html

为什么你需要经常删除数组的块?如果您的数组非常动态,则最好使用 alist来存储数组的各个部分,并且一次只删除较小的位。

于 2012-05-14T19:41:48.080 回答