NumPy中的行交换

23

在Python中,我可以通过多赋值来交换两个变量; 它也适用于列表:

l1,l2=[1,2,3],[4,5,6]
l1,l2=l2,l1
print(l1,l2)
>>> [4, 5, 6] [1, 2, 3]

但是当我想要交换一个NumPy数组的两行(例如在高斯算法中),它失败了:

import numpy as np
a3=np.array([[1,2,3],[4,5,6]])
print(a3)
a3[0,:],a3[1,:]=a3[1,:],a3[0,:]
print(a3)
>>> [[1 2 3]
     [4 5 6]]
    [[4 5 6]
     [4 5 6]]

我曾以为由于某种奇怪的原因,这两列现在指向相同的值;但事实并非如此,因为在之前的行中,a3[0,0]=5 改变了 a3[0,0] 而不是 a3[1,0]。

我已经找到了解决这个问题的方法:例如 a3[0,:],a3[1,:]=a3[1,:].copy(),a3[0,:].copy() 是有效的。但是有人能解释一下为什么用多重赋值交换 numpy 的行会失败吗?我的问题涉及到 Python 和 Numpy 的底层工作。


2
请参考 这个问题的答案 以获取解释。 - user4815162342
好的,谢谢,这个问题在可能重复的列表中没有自动提出。 - JPG
没问题 - 我知道它的唯一原因是因为我回答了它。 - user4815162342
1个回答

40

这将按照您的意图工作:

a3[[0,1]] = a3[[1,0]]

元组赋值中的两个独立赋值在彼此之间没有缓冲;一个发生在另一个之后,导致覆盖你所观察到的


很好,当你尝试执行a[[0, 1, 1]] += 1时,位置为1的项只会被增加一次,这可能是一个麻烦,但也可以用于交换行。 - Jaime
是的,我花了一段时间才开始欣赏它背后的逻辑。现在非常满意新的np.add.at;事实上,我正在用它编写一段代码,这曾经是一个可怕的缓慢的Python循环。 - Eelco Hoogendoorn
对于求和,np.bincount通常比np.add.at快得多,在我刚刚尝试的这个例子中快了50倍:a = np.zeros((1000,), dtype=np.intp); b = np.random.randint(1000, size=100000); c = np.random.randint(1000000, size=100000); In [10]: %timeit np.add.at(a, b, c); 100 loops, best of 3: 19.3 ms per loop; In [11]: %timeit a + np.bincount(b, weights=c, minlength=1000); 1000 loops, best of 3: 451 µs per loop - Jaime
当然,可读性会受到严重影响,而且很难想象出这种操作会成为瓶颈的情况。但是,如果您想要原始性能,那么这似乎是正确的方法。 - Jaime
这让我非常惊讶。你会认为np.add.at的实现是最基本的循环,但它也可以推广到nd-arrays的散射,所以可能会增加一些开销?但我无法想象40这个因素来自哪里。 - Eelco Hoogendoorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接