2017-02-21 193 views
1

我想製作給定二維數組的多個副本,並將它們存儲爲3D numpy數組的通道。目前,我有以下內容:將2D numpy陣列有效地複製爲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

Loop'for i in range(fin alOut。形狀[-1]):' - 最後尺寸的大小,而不是尺寸的數量(它們恰好都是3)。 – hpaulj

+0

謝謝hpaulj。更正! – GKS

回答

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前後適用於正確的形狀(S)。

使用廣播有多種方式,但它們似乎沒有更快。

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 

我還在猶豫表明這一點,因爲我認爲這將是創建視圖,而不是複印件。但初步測試表明它正在複製。

+0

我同意沒有太多的速度增益範圍 – GKS

+0

我發現一個更快的,我認爲 – hpaulj

+0

謝謝hpaulj,它總體上看起來更快,但我得到的非常微不足道的速度增益。 – GKS

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]]]) 

然後,新的三維陣列是連構造直到操作是在通道進行。但是這需要一些時間來適應......

+0

不知道是否np.rollaxis(b,0,3)輸出是我想要的。雖然形狀現在是適當的,但是當我從我的方法和方法中減去最終輸出時,絕對差異是巨大的 – GKS

+0

@GKS我編輯了我的答案以替代使用轉置,並且我添加了一個測試以向您顯示有用。這有幫助嗎? – Praveen

+0

但它確實有幫助,但它仍然不會更快。非常感謝 – GKS

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