将2D numpy数组复制为3D numpy数组的通道有效吗?

时间:2017-02-21 01:50:36

标签: python arrays numpy

我想制作给定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

这是最快的方法吗?

3 个答案:

答案 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