2015-08-23 202 views

回答

34

也許最乾淨的方法是使用np.repeat

a = np.array([[1, 2], [1, 2]]) 
print(a.shape) 
# (2, 2) 

# indexing with np.newaxis inserts a new 3rd dimension, which we then repeat the 
# array along, (you can achieve the same effect by indexing with None, see below) 
b = np.repeat(a[:, :, np.newaxis], 3, axis=2) 

print(b.shape) 
# (2, 2, 3) 

print(b[:, :, 0]) 
# [[1 2] 
# [1 2]] 

print(b[:, :, 1]) 
# [[1 2] 
# [1 2]] 

print(b[:, :, 2]) 
# [[1 2] 
# [1 2]] 

說了這麼多,你可以經常避免重蹈你的陣列總共使用broadcasting。例如,假設我想添加一個(3,)向量:

c = np.array([1, 2, 3]) 

a。我可以在第三維中複製a 3次的內容,然後在第一維和第二維中複製c的內容兩次,以便我的兩個數組都是(2, 2, 3),然後計算它們的總和。然而,這是更簡單,更快地做到這一點:

d = a[..., None] + c[None, None, :] 

這裏,a[..., None]具有形狀(2, 2, 1)c[None, None, :]具有形狀(1, 1, 3) *。當我計算總和,結果獲得「廣播」一起尺寸1的尺寸了,給我塑造(2, 2, 3)的結果:

print(d.shape) 
# (2, 2, 3) 

print(d[..., 0]) # a + c[0] 
# [[2 3] 
# [2 3]] 

print(d[..., 1]) # a + c[1] 
# [[3 4] 
# [3 4]] 

print(d[..., 2]) # a + c[2] 
# [[4 5] 
# [4 5]] 

廣播是一個非常強大的技術,因爲它避免了參與創建的額外開銷在內存中重複輸入數組的副本。


*雖然我包括他們清楚,None指數爲c沒有實際需要 - 你也可以做a[..., None] + c,即廣播針對(3,)陣列(2, 2, 1)陣列。這是因爲如果其中一個陣列的尺寸比另一個小,那麼只有兩個陣列的尺寸需要兼容。舉一個更復雜的例子:

a = np.ones((6, 1, 4, 3, 1)) # 6 x 1 x 4 x 3 x 1 
b = np.ones((5, 1, 3, 2))  #  5 x 1 x 3 x 2 
result = a + b    # 6 x 5 x 4 x 3 x 2 
+0

要驗證這確實給出正確的結果,也可以打印出來'b [:,:,0]','b [:,:,1]'和'b [:,:,2]'。每個第三維切片都是原始二維數組的副本。這只是看着'print(b)'而已。 – ely

+0

這是一個很好的答案!謝謝! – drg

11

另一種方法是使用numpy.dstack。假設你要重複的矩陣anum_repeats時間:

import numpy as np 
b = np.dstack([a]*num_repeats) 

訣竅是矩陣a包裝成一個單一的元素的列表,然後使用*操作複製的元素在此列表中num_repeats倍。

例如,如果:

a = np.array([[1, 2], [1, 2]]) 
num_repeats = 5 

這重複的[1 2; 1 2] 5次在第三維陣列。爲了驗證(在IPython的):

In [110]: import numpy as np 

In [111]: num_repeats = 5 

In [112]: a = np.array([[1, 2], [1, 2]]) 

In [113]: b = np.dstack([a]*num_repeats) 

In [114]: b[:,:,0] 
Out[114]: 
array([[1, 2], 
     [1, 2]]) 

In [115]: b[:,:,1] 
Out[115]: 
array([[1, 2], 
     [1, 2]]) 

In [116]: b[:,:,2] 
Out[116]: 
array([[1, 2], 
     [1, 2]]) 

In [117]: b[:,:,3] 
Out[117]: 
array([[1, 2], 
     [1, 2]]) 

In [118]: b[:,:,4] 
Out[118]: 
array([[1, 2], 
     [1, 2]]) 

In [119]: b.shape 
Out[119]: (2, 2, 5) 

最後,我們可以看到,基體的形狀是2 x 2,與在第三維5片。

+0

這與「重塑」相比如何?更快?給出相同的結構?它絕對整潔。 –

+0

@AnderBiguri我從來沒有做過基準測試......我把它放在這裏主要是爲了完整。時間和看到差異會很有趣。 – rayryeng

+1

我只是做了img = np.dstack([arr] * 3)並且工作正常!謝謝 –

2
A=np.array([[1,2],[3,4]]) 
B=np.asarray([A]*N) 

編輯@ Mr.F,維護維序:

B=B.T 
+0

這導致我爲N×2×2陣列,例如'B.shape'爲'N'的任何值打印'(N,2,2)'。如果你用'B.T'轉置'B',那麼它匹配預期的輸出。 – ely

+0

@ Mr.F - 你是對的。這將沿着第一維進行廣播,所以'B [0],B [1],...'會給你正確的分片,我會爭辯說,輸入更容易,而不是使用'B [:,:,0],B [:,:,1]'等等。 – rayryeng

+0

鍵入起來可能更容易,但是例如,如果你用圖像數據做這件事,它很可能是不正確的,因爲幾乎所有的算法都會期望線性代數的慣例被用於像素通道的2D切片。很難想象一個以2D數組開頭的應用程序,按照一定的慣例處理行和列,然後想要將同一事物的多個副本擴展到新軸,但突然想要第一個軸將含義改爲成爲新的軸... – ely

1

這裏有一個廣播的例子,不被要求什麼。

a = np.array([[1, 2], [1, 2]]) 
a=a[:,:,None] 
b=np.array([1]*5)[None,None,:] 

然後b*a是理想的結果和(b*a)[:,:,0]產生array([[1, 2],[1, 2]]),這是原來a一樣,(b*a)[:,:,1]