我想在沒有 for 回圈的情況下修改 3d 陣列的塊元素。沒有回圈,因為它是我的代碼的瓶頸。
為了說明我想要什么,我畫了一個圖:
帶有for回圈的代碼:
import numpy as np
# Create 3d array with 2x4x4 elements
a = np.arange(2*4*4).reshape(2,4,4)
b = np.zeros(np.shape(a))
# Change Block Elements
for it1 in range(2):
b[it1]= np.block([[a[it1,0:2,0:2], a[it1,2:4,0:2]],[a[it1,0:2,2:4], a[it1,2:4,2:4]]] )
uj5u.com熱心網友回復:
reshape
首先讓我們看看是否有一種方法可以僅使用索引、 和操作來為 2D 陣列執行您想要的transpose
操作。如果有,那么您很有可能可以將其擴展到更多維度。
x = np.arange(2 * 3 * 2 * 5).reshape(2 * 3, 2 * 5)
顯然,您可以將其重塑為具有沿單獨維度的塊的陣列:
x.reshape(2, 3, 2, 5)
然后您可以轉置生成的塊:
x.reshape(2, 3, 2, 5).transpose(2, 1, 0, 3)
到目前為止,沒有任何資料被復制。要進行復制,請重新整形為原始形狀:
x.reshape(2, 3, 2, 5).transpose(2, 1, 0, 3).reshape(2 * 3, 2 * 5)
添加其他前導維度就像增加要交換的維度數量一樣簡單:
b = a.reshape(a.shape[0], 2, a.shape[1] // 2, 2, a.shape[2] // 2).transpose(0, 3, 2, 1, 4).reshape(a.shape)
這是使用原始陣列的其他實作的快速基準:
a = np.arange(2*4*4).reshape(2,4,4)
%%timeit
b = np.zeros(np.shape(a))
for it1 in range(2):
b[it1] = np.block([[a[it1, 0:2, 0:2], a[it1, 2:4, 0:2]], [a[it1, 0:2, 2:4], a[it1, 2:4, 2:4]]])
27.7 μs ± 107 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
b = a.copy()
b[:,0:2,2:4], b[:,2:4,0:2] = b[:,2:4,0:2].copy(), b[:,0:2,2:4].copy()
2.22 μs ± 3.89 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit b = np.block([[a[:,0:2,0:2], a[:,2:4,0:2]],[a[:,0:2,2:4], a[:,2:4,2:4]]])
13.6 μs ± 217 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit b = a.reshape(a.shape[0], 2, a.shape[1] // 2, 2, a.shape[2] // 2).transpose(0, 3, 2, 1, 4).reshape(a.shape)
1.27 μs ± 14.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
對于小型陣列,差異有時可歸因于開銷。這是一個更有意義的比較,大小為 10x1000x1000 的陣列,分成 10 個 500x500 塊:
a = np.arange(10*1000*1000).reshape(10, 1000, 1000)
%%timeit
b = np.zeros(np.shape(a))
for it1 in range(10):
b[it1]= np.block([[a[it1,0:500,0:500], a[it1,500:1000,0:500]],[a[it1,0:500,500:1000], a[it1,500:1000,500:1000]]])
58 ms ± 904 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
b = a.copy()
b[:,0:500,500:1000], b[:,500:1000,0:500] = b[:,500:1000,0:500].copy(), b[:,0:500,500:1000].copy()
41.2 ms ± 688 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit b = np.block([[a[:,0:500,0:500], a[:,500:1000,0:500]],[a[:,0:500,500:1000], a[:,500:1000,500:1000]]])
27.5 ms ± 569 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit b = a.reshape(a.shape[0], 2, a.shape[1] // 2, 2, a.shape[2] // 2).transpose(0, 3, 2, 1, 4).reshape(a.shape)
20 ms ± 161 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
所以看來在我的電腦上使用numpy自己的reshaping和transposition機制是最快的。另外,請注意,np.block
隨著大小變得越來越大,與復制臨時陣列相比,開銷變得不那么重要,因此其他兩個實作改變了位置。
uj5u.com熱心網友回復:
您可以直接將 替換it1
為整個維度的切片:
b = np.block([[a[:,0:2,0:2], a[:,2:4,0:2]],[a[:,0:2,2:4], a[:,2:4,2:4]]])
uj5u.com熱心網友回復:
它會讓它更快嗎?
import numpy as np
a = np.arange(2*4*4).reshape(2,4,4)
b = a.copy()
b[:,0:2,2:4], b[:,2:4,0:2] = b[:,2:4,0:2].copy(), b[:,0:2,2:4].copy()
與另一個答案的 np.block() 替代方案進行比較。
選項 1:
%timeit b = a.copy(); b[:,0:2,2:4], b[:,2:4,0:2] = b[:,2:4,0:2].copy(), b[:,0:2,2:4].copy()
輸出:
5.44 μs ± 134 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
選項 2
%timeit b = np.block([[a[:,0:2,0:2], a[:,2:4,0:2]],[a[:,0:2,2:4], a[:,2:4,2:4]]])
輸出:
30.6 μs ± 1.75 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/507383.html