簡體   English   中英

在numpy中將幾個小矩陣分配到一個大矩陣上的最有效方法

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

由於Cnp.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM