我想將numpy 2D數組複製到第三維。例如,如果我有這樣的(2D)numpy的數組:將二維數組複製到第三維,N次(Python)
import numpy as np
arr = np.array([[1,2],[1,2]])
它轉換成具有N個這樣的拷貝的3D矩陣的新領域,像這樣對N = 3:
np.array([[[1,2],[1,2]],[[1,2],[1,2]],[[1,2],[1,2]]])
我想將numpy 2D數組複製到第三維。例如,如果我有這樣的(2D)numpy的數組:將二維數組複製到第三維,N次(Python)
import numpy as np
arr = np.array([[1,2],[1,2]])
它轉換成具有N個這樣的拷貝的3D矩陣的新領域,像這樣對N = 3:
np.array([[[1,2],[1,2]],[[1,2],[1,2]],[[1,2],[1,2]]])
也許最乾淨的方法是使用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
另一種方法是使用numpy.dstack
。假設你要重複的矩陣a
num_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片。
這與「重塑」相比如何?更快?給出相同的結構?它絕對整潔。 –
@AnderBiguri我從來沒有做過基準測試......我把它放在這裏主要是爲了完整。時間和看到差異會很有趣。 – rayryeng
我只是做了img = np.dstack([arr] * 3)並且工作正常!謝謝 –
A=np.array([[1,2],[3,4]])
B=np.asarray([A]*N)
編輯@ Mr.F,維護維序:
B=B.T
這導致我爲N×2×2陣列,例如'B.shape'爲'N'的任何值打印'(N,2,2)'。如果你用'B.T'轉置'B',那麼它匹配預期的輸出。 – ely
@ Mr.F - 你是對的。這將沿着第一維進行廣播,所以'B [0],B [1],...'會給你正確的分片,我會爭辯說,輸入更容易,而不是使用'B [:,:,0],B [:,:,1]'等等。 – rayryeng
鍵入起來可能更容易,但是例如,如果你用圖像數據做這件事,它很可能是不正確的,因爲幾乎所有的算法都會期望線性代數的慣例被用於像素通道的2D切片。很難想象一個以2D數組開頭的應用程序,按照一定的慣例處理行和列,然後想要將同一事物的多個副本擴展到新軸,但突然想要第一個軸將含義改爲成爲新的軸... – ely
這裏有一個廣播的例子,不被要求什麼。
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]
等
要驗證這確實給出正確的結果,也可以打印出來'b [:,:,0]','b [:,:,1]'和'b [:,:,2]'。每個第三維切片都是原始二維數組的副本。這只是看着'print(b)'而已。 – ely
這是一個很好的答案!謝謝! – drg