交换Numpy数组的切片

38

我喜欢Python处理变量交换的方式: a, b, = b, a

我也想利用这种功能来交换数组之间的值,不仅限于一次交换一个,而是多个(不使用临时变量)。但它并不符合我的期望(我希望两个维度上的所有数值都可以同时交换):

import numpy as np
a = np.random.randint(0, 10, (2, 3,3))
b = np.random.randint(0, 10, (2, 5,5))
# display before
a[:,0, 0]
b[:,0,0]
a[:,0,0], b[:, 0, 0] = b[:, 0, 0], a[:,0,0] #swap
# display after
a[:,0, 0]
b[:,0,0]

有人有想法吗?当然,我可以引入一个额外的变量,但我想知道是否有更优雅的方法来做到这一点。


我最喜欢的方法在这里:https://dev59.com/qm445IYBdhLWcg3wcJ6O#4857981(高级切片) - David Ketcheson
4个回答

30

Python会正确地解释代码,就像您使用了其他变量一样,因此交换代码等效于:

t1 = b[:,0,0]
t2 = a[:,0,0]
a[:,0,0] = t1
b[:,0,0] = t2

然而,即使这段代码使用了this,它仍然不能正确地交换值!这是因为Numpy的切片不会立即复制数据,它们只是创建了现有数据的视图。只有在切片被赋值时才执行复制操作,但是当交换时,没有中间缓冲区的复制会破坏您的数据。这就是为什么您不仅需要一个额外的变量,还需要一个额外的numpy缓冲区,而一般的Python语法无法知道这一点。例如,以下代码可以按预期工作:
t = np.copy(a[:,0,0])
a[:,0,0] = b[:,0,0]
b[:,0,0] = t

11
我认为这是最简单的方法:
a[:,0,0], b[:, 0, 0] = b[:, 0, 0], a[:, 0, 0].copy() #swap

时间比较:

%timeit a[:,0,0], b[:, 0, 0] = b[:, 0, 0], a[:, 0, 0].copy() #swap
The slowest run took 10.79 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 1.75 µs per loop

%timeit t = np.copy(a[:,0,0]); a[:,0,0] = b[:,0,0]; b[:,0,0] = t
The slowest run took 10.88 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 2.68 µs per loop

1

user4815162342的答案确实是“正确”的答案。但如果你真的想要一个一行代码的解决方案,那么可以考虑以下内容:

a[arange(2),0,0], b[arange(2), 0, 0] = b[arange(2), 0, 0], a[arange(2),0,0] #swap

然而,这种方法的效率要低得多:

In [12]: %timeit a[arange(2),0,0], b[arange(2), 0, 0] = b[arange(2), 0, 0], a[arange(2),0,0]
10000 loops, best of 3: 32.2 µs per loop

In [13]: %timeit t = np.copy(a[:,0,0]); a[:,0,0] = b[:,0,0]; b[:,0,0] = t
The slowest run took 4.14 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 13.3 µs per loop

(但请注意关于“最慢运行”的注释...如果您尝试使用“-n 1 -r 1”调用%timeit,则会看到更可比较的结果-尽管我的解决方案仍然慢约50%-说明是的,缓存正在影响计时)


-1

这将会起作用。

a[:,0,0], b[:, 0, 0] = b[:, 0, 0].copy(), a[:, 0, 0].copy()

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