[英]The most efficient way to assign several small matrices onto a large matrix in numpy
我有一個形狀為 (10, 10) 的大矩陣 A
array([[2, 1, 2, 1, 1, 4, 3, 2, 2, 2],
[3, 2, 1, 2, 3, 3, 2, 3, 2, 4],
[1, 3, 3, 4, 2, 4, 4, 3, 4, 1],
[1, 3, 1, 3, 3, 1, 4, 2, 1, 2],
[3, 3, 1, 3, 3, 2, 3, 4, 3, 2],
[2, 4, 1, 4, 2, 1, 1, 2, 1, 1],
[2, 3, 2, 3, 1, 4, 3, 1, 2, 3],
[3, 1, 3, 2, 2, 4, 2, 3, 3, 3],
[1, 2, 3, 2, 1, 3, 4, 4, 1, 3],
[3, 1, 3, 2, 4, 3, 1, 1, 1, 1]])
和形狀為 (5, 2) 的位置數組 B
array([[4, 5], # row 4, column 5
[2, 1],
[2, 5],
[4, 1],
[6, 7]])
和幾個形狀為 (5, 2, 2) 的小矩陣 C
array([[[7, 9],
[6, 7]],
[[6, 6],
[9, 6]],
[[9, 6],
[8, 9]],
[[8, 7],
[8, 7]],
[[8, 6],
[7, 7]]])
現在,我想將這 5 個小矩陣分配給大矩陣。 這些位置是小矩陣左上角的位置。 如果存在重疊區域,我們可以使用最后一個,最大值或僅求和。 我想要的效果看起來像
A[B] += C
for 循環實現如下所示:
for i in range(B.shape[0]):
A[B[i][0]:B[i][0]+2,B[i][1]:B[i][1]+2] += C[i]
預期的結果看起來像
array([[ 2, 1, 2, 1, 1, 4, 3, 2, 2, 2],
[ 3, 2, 1, 2, 3, 3, 2, 3, 2, 4],
[ 1, 9, 9, 4, 2, 13, 10, 3, 4, 1],
[ 1, 12, 7, 3, 3, 9, 13, 2, 1, 2],
[ 3, 11, 8, 3, 3, 9, 12, 4, 3, 2],
[ 2, 12, 8, 4, 2, 7, 8, 2, 1, 1],
[ 2, 3, 2, 3, 1, 4, 3, 9, 8, 3],
[ 3, 1, 3, 2, 2, 4, 2, 10, 10, 3],
[ 1, 2, 3, 2, 1, 3, 4, 4, 1, 3],
[ 3, 1, 3, 2, 4, 3, 1, 1, 1, 1]])
有沒有沒有for循環的解決方案?
一個簡單的 forloop 可以解決這個問題:
import numpy as np
initial = np.array([
[2, 1, 2, 1, 1, 4, 3, 2, 2, 2], [3, 2, 1, 2, 3, 3, 2, 3, 2, 4], [1, 3, 3, 4, 2, 4, 4, 3, 4, 1], [1, 3, 1, 3, 3, 1, 4, 2, 1, 2],
[3, 3, 1, 3, 3, 2, 3, 4, 3, 2], [2, 4, 1, 4, 2, 1, 1, 2, 1, 1], [2, 3, 2, 3, 1, 4, 3, 1, 2, 3], [3, 1, 3, 2, 2, 4, 2, 3, 3, 3],
[1, 2, 3, 2, 1, 3, 4, 4, 1, 3], [3, 1, 3, 2, 4, 3, 1, 1, 1, 1],
])
offsets = np.array([[4, 5], [2, 1], [2, 5], [4, 1], [6, 7]])
subarrays = np.array([
[[7, 9], [6, 7]], [[6, 6], [9, 6]], [[9, 6], [8, 9]],
[[8, 7], [8, 7]], [[8, 6], [7, 7]],
])
for subarray, offset in zip(subarrays, offsets):
(a, b), (c, d) = offset, subarray.shape
initial[a:a+c, b:b+d] += subarray
print(initial)
你的數組:
In [58]: A = np.array([[2, 1, 2, 1, 1, 4, 3, 2, 2, 2],
...: [3, 2, 1, 2, 3, 3, 2, 3, 2, 4],
...: [1, 3, 3, 4, 2, 4, 4, 3, 4, 1],
...: [1, 3, 1, 3, 3, 1, 4, 2, 1, 2],
...: [3, 3, 1, 3, 3, 2, 3, 4, 3, 2],
...: [2, 4, 1, 4, 2, 1, 1, 2, 1, 1],
...: [2, 3, 2, 3, 1, 4, 3, 1, 2, 3],
...: [3, 1, 3, 2, 2, 4, 2, 3, 3, 3],
...: [1, 2, 3, 2, 1, 3, 4, 4, 1, 3],
...: [3, 1, 3, 2, 4, 3, 1, 1, 1, 1]])
In [59]: B=np.array([[4, 5], # row 4, column 5
...: [2, 1],
...: [2, 5],
...: [4, 1],
...: [6, 7]])
In [60]: C=np.array([[[7, 9],
...: [6, 7]],
...:
...: [[6, 6],
...: [9, 6]],
...:
...: [[9, 6],
...: [8, 9]],
...:
...: [[8, 7],
...: [8, 7]],
...:
...: [[8, 6],
...: [7, 7]]])
你的迭代,清理了一下:
In [72]: for cnt,(i,j) in enumerate(B):
...: A[i:i+2, j:j+2] += C[cnt]
...:
In [73]: A
Out[73]:
array([[ 2, 1, 2, 1, 1, 4, 3, 2, 2, 2],
[ 3, 2, 1, 2, 3, 3, 2, 3, 2, 4],
[ 1, 9, 9, 4, 2, 13, 10, 3, 4, 1],
[ 1, 12, 7, 3, 3, 9, 13, 2, 1, 2],
[ 3, 11, 8, 3, 3, 9, 12, 4, 3, 2],
[ 2, 12, 8, 4, 2, 7, 8, 2, 1, 1],
[ 2, 3, 2, 3, 1, 4, 3, 9, 8, 3],
[ 3, 1, 3, 2, 2, 4, 2, 10, 10, 3],
[ 1, 2, 3, 2, 1, 3, 4, 4, 1, 3],
[ 3, 1, 3, 2, 4, 3, 1, 1, 1, 1]])
為了讓動作更清晰,讓我們從一個 0 數組開始:
In [76]: A = np.zeros_like(Acopy)
In [77]: for cnt,(i,j) in enumerate(B):
...: A[i:i+2, j:j+2] += C[cnt]
...:
In [78]: A
Out[78]:
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 6, 6, 0, 0, 9, 6, 0, 0, 0],
[0, 9, 6, 0, 0, 8, 9, 0, 0, 0],
[0, 8, 7, 0, 0, 7, 9, 0, 0, 0],
[0, 8, 7, 0, 0, 6, 7, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 8, 6, 0],
[0, 0, 0, 0, 0, 0, 0, 7, 7, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
我沒有看到重疊,所以我認為我們可以從B
構造一個索引數組,這將使我們能夠:
A[B1] += C
如果有重疊,它將寫入最后一個C
值。
如果我們不喜歡這樣,有np.add.at
ufunc
可以執行緩沖除(甚至np.max.at
)。
但是需要一些時間來計算出所需的B1
指數。
這是一種使用+=
。 我正在使用linspace
構建一個多維索引,它將用於代替切片。 獲得正確的形狀需要大量的反復試驗和測試(在交互式會話中)。 只要塊不重疊,這就是快速且正確的。 但是正如np.add.at
所記錄的np.add.at
,當存在重復索引時,這與迭代方法不匹配。
In [125]: B1 = B+2
In [126]: I = np.linspace(B,B1,2,endpoint=False).astype(int)
In [127]: A1 =np.zeros_like(Acopy)
In [128]: A1[I[:,:,0][:,None], I[:,:,1]] += C.transpose(1,2,0)
In [129]: np.allclose(A1,A)
Out[129]: True
I
是一個 (2,5,2) 形狀的數組,其中“步數”中的前 2 個 In [130]: I Out[130]: array([[[4, 5], [2, 1] , [2, 5], [4, 1], [6, 7]],
[[5, 6],
[3, 2],
[3, 6],
[5, 2],
[7, 8]]])
由於C
子np.stack([B,B+1])
是 (2,2),這與: np.stack([B,B+1])
需要C
轉置,因為A1
這個索引產生一個 (2,2,5) 數組:
In [134]: A1[I[:,:,0][:,None], I[:,:,1]]
Out[134]:
array([[[7, 6, 9, 8, 8],
[9, 6, 6, 7, 6]],
[[6, 9, 8, 8, 7],
[7, 6, 9, 7, 7]]])
In [135]: _.shape
Out[135]: (2, 2, 5)
如果某些塊重疊,可以使用np.add.at
對重疊進行求和:
In [137]: A1 =np.zeros_like(Acopy)
In [138]: np.add.at(A1, (I[:,:,0][:,None], I[:,:,1]), C.transpose(1,2,0))
In [140]: np.allclose(A1,A)
Out[140]: True
或最大的
In [143]: np.maximum.at(A1, (I[:,:,0][:,None], I[:,:,1]), C.transpose(1,2,0))
In [144]: np.allclose(A1,A)
看,我試過的,沒有使用任何類型的循環
import numpy as np
A=np.array([[2, 1, 2, 1, 1, 4, 3, 2, 2, 2],
[3, 2, 1, 2, 3, 3, 2, 3, 2, 4],
[1, 3, 3, 4, 2, 4, 4, 3, 4, 1],
[1, 3, 1, 3, 3, 1, 4, 2, 1, 2],
[3, 3, 1, 3, 3, 2, 3, 4, 3, 2],
[2, 4, 1, 4, 2, 1, 1, 2, 1, 1],
[2, 3, 2, 3, 1, 4, 3, 1, 2, 3],
[3, 1, 3, 2, 2, 4, 2, 3, 3, 3],
[1, 2, 3, 2, 1, 3, 4, 4, 1, 3],
[3, 1, 3, 2, 4, 3, 1, 1, 1, 1]])
B= np.array([[4, 5], # row 4, column 5
[2, 1],
[2, 5],
[4, 1],
[6, 7]])
C=np.array([[[7, 9],
[6, 7]],
[[6, 6],
[9, 6]],
[[9, 6],
[8, 9]],
[[8, 7],
[8, 7]],
[[8, 6],
[7, 7]]])
D= np.array([[ 2, 1, 2, 1, 1, 4, 3, 2, 2, 2], # this is required
[ 3, 2, 1, 2, 3, 3, 2, 3, 2, 4],
[ 1, 9, 9, 4, 2, 13, 10, 3, 4, 1],
[ 1, 12, 7, 3, 3, 9, 13, 2, 1, 2],
[ 3, 11, 8, 3, 3, 9, 12, 4, 3, 2],
[ 2, 12, 8, 4, 2, 7, 8, 2, 1, 1],
[ 2, 3, 2, 3, 1, 4, 3, 9, 8, 3],
[ 3, 1, 3, 2, 2, 4, 2, 10, 10, 3],
[ 1, 2, 3, 2, 1, 3, 4, 4, 1, 3],
[ 3, 1, 3, 2, 4, 3, 1, 1, 1, 1]])
我們需要 A==D。 我為 C 的所有值創建了行和列索引。
b_row=np.repeat(np.c_[B[:,0],B[:,0]+1], repeats=2, axis=1).ravel()
b_col=np.repeat(np.c_[B[:,1],B[:,1]+1], repeats=2, axis=0).ravel()
print(np.c_[bx,by]) # to see indexes
A[b_row,b_col]+=C.ravel()
現在你可以檢查
print(A==D)
False in (A==D)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.