我想制作给定2D数组的多个副本,并将它们存储为3D numpy数组的通道。目前,我有以下内容:
finalOut=np.zeros((800,400,3))
output_frame=np.random.randn(800,400)
for i in range(finalOut.shape[-1]):
finalOut[:,:,i]=output_frame
这是最快的方法吗?
答案 0 :(得分:2)
def gks(frame):
finalOut=np.zeros((800,400,3))
for i in range(finalOut.shape[-1]):
finalOut[:,:,i]=frame
return finalOut
对于此尺寸,您的代码与tile
解决方案一样好:
In [52]: frame = np.random.randn(800,400)
In [61]: np.allclose(gks(frame), np.tile(frame[:,:,None],[1,1,3]))
Out[61]: True
In [62]: timeit np.tile(frame[:,:,None],[1,1,3]).shape
100 loops, best of 3: 9.36 ms per loop
In [63]: timeit gks(frame).shape
100 loops, best of 3: 9.36 ms per loop
np.tile
代码使用repeat
(已编译)进行复制,并使用reshape
之前和之后将其应用于正确的形状。
有多种使用广播的方式,但它们似乎没有更快。
In [70]: timeit (frame[:,:,None]+np.zeros(3)).shape
100 loops, best of 3: 11.6 ms per loop
你的循环很好,因为与整个数组大小相比,大小3很小。
这是更快的事情:
def spl(frame):
finalOut=np.zeros((800,400,3))
finalOut[...]=frame[...,None]
return finalOut
In [105]: timeit spl(frame)
100 loops, best of 3: 5.54 ms per loop
我犹豫不决,因为我认为它会创建视图,而不是副本。但初步测试表明它正在复制。
答案 1 :(得分:1)
使用np.tile
。
>>> a = np.array([[1, 2, 3],
[4, 5, 6]])
>>> np.tile(a, (3, 1, 1))
array([[[1, 2, 3],
[4, 5, 6]],
[[1, 2, 3],
[4, 5, 6]],
[[1, 2, 3],
[4, 5, 6]]])
当然,这会将频道放在第0轴,所以您可能希望之后使用np.transpose
移动频道:
>>> b = np.tile(a, (3, 1, 1))
>>> np.transpose(b, (1, 2, 0))
array([[[1, 1, 1],
[2, 2, 2],
[3, 3, 3]],
[[4, 4, 4],
[5, 5, 5],
[6, 6, 6]]])
>>> np.transpose(b, (1, 2, 0)).shape
(2, 3, 3)
<强>测试强>
>>> d = np.transpose(b, (1, 2, 0))
>>> c = np.zeros((2, 3, 3))
>>> for i in range(3): c[:, :, i] = a[:, :]
>>> np.allclose(c, d)
True
最快的选择通常是使用numpy broadcasting,它允许您创建一个新轴,并且在必要时不使用它。例如:
>>> b = a[:, :, np.newaxis]
>>> b.shape
(2, 3, 1)
>>> b = b * np.array([1, 0, 0]) # Set G and B channels to 0.
>>> b
array([[[1, 0, 0],
[2, 0, 0],
[3, 0, 0]],
[[4, 0, 0],
[5, 0, 0],
[6, 0, 0]]])
然后,甚至不构造新的3D阵列,直到对通道执行操作。但它需要一些习惯......
答案 2 :(得分:1)
您也可以使用np.dstack
:
import numpy as np
def copy_dstack(frame):
return np.dstack((frame,)*3)
def copy_for(frame):
arr = np.zeros(shape=frame.shape + (3,))
for i in range(arr.shape[-1]):
arr[:, :, i] = frame
return arr
def copy_tile(frame):
return np.tile(frame[:, :, None], [1, 1, 3])
def copy_broadcasting(frame):
arr = np.zeros(shape=frame.shape + (3,))
arr[...] = frame[..., None]
return arr
根据我的测试,@ hpaulj和@Praveen提出的方法比你的慢,而我的速度可以忽略不计:
In [244]: frame = np.random.randn(800, 400)
In [245]: %timeit copy_dstack(frame)
100 loops, best of 3: 4.07 ms per loop
In [246]: %timeit copy_for(frame)
100 loops, best of 3: 4.1 ms per loop
In [247]: %timeit copy_tile(frame)
100 loops, best of 3: 6.8 ms per loop
In [248]: %timeit copy_broadcasting(frame)
100 loops, best of 3: 6.71 ms per loop
我还检查了所有方法产生相同的结果:
In [249]: np.allclose(copy_dstack(frame), copy_for(frame))
Out[249]: True
In [250]: np.allclose(copy_for(frame), copy_tile(frame))
Out[250]: True
In [251]: np.allclose(copy_tile(frame), copy_broadcasting(frame))
Out[251]: True