簡體   English   中英

numpy:從子矩陣廣播

[英]Numpy: Broadcasting from submatrix

給定兩個2D數組:

A =[[1, 1, 2, 2],
    [1, 1, 2, 2],
    [3, 3, 4, 4],
    [3, 3, 4, 4]]

B =[[1, 2],
    [3, 4]]

A - B = [[ 0, -1,  1,  0],
         [-2, -3, -1, -2],
         [ 2,  1,  3,  2],
         [ 0, -1,  1,  0]]

B的形狀為2,2,A的形狀為4,4。 我想對A進行廣播減法B:A-B。

我特別想使用廣播,因為我要處理的陣列大小非常大(8456,8456)。 我希望廣播將提供一個小的性能優化。

我試過重塑數組,但沒有運氣,而且很困惑。 我無法使用Scikit。

您可以通過將B在兩個維度上平鋪兩次來展開B

print A - numpy.tile(B, (2, 2))

產量

[[ 0 -1  1  0]
 [-2 -3 -1 -2]
 [ 2  1  3  2]
 [ 0 -1  1  0]]

但是,對於大型矩陣,這可能會在RAM中產生大量開銷。

或者,您可以使用Scikit Image的skimage.util.view_as_blocks 塊查看A並在適當位置進行修改

Atmp = skimage.util.view_as_blocks(A, block_shape=(2, 2))
Atmp -= B

print A

這將導致,而無需不必要地重復B

[[ 0 -1  1  0]
 [-2 -3 -1 -2]
 [ 2  1  3  2]
 [ 0 -1  1  0]]

方法#1:這是一種使用strides的方法,該方法使用views的概念而無需制作實際副本即可從A減去,因此應該非常有效-

m,n = B.strides
m1,n1 = A.shape
m2,n2 = B.shape
s1,s2 = m1//m2, n1//n2
strided = np.lib.stride_tricks.as_strided         
out = A - strided(B,shape=(s1,m2,s2,n2),strides=(0,n2*n,0,n)).reshape(A.shape)

樣品運行-

In [78]: A
Out[78]: 
array([[29, 53, 30, 25, 92, 10],
       [ 2, 20, 35, 87,  0,  9],
       [46, 30, 20, 62, 79, 63],
       [44,  9, 78, 33,  6, 40]])

In [79]: B
Out[79]: 
array([[35, 60],
       [21, 86]])

In [80]: m,n = B.strides
    ...: m1,n1 = A.shape
    ...: m2,n2 = B.shape
    ...: s1,s2 = m1//m2, n1//n2
    ...: strided = np.lib.stride_tricks.as_strided
    ...: 

In [81]: # Replicated view
    ...: strided(B,shape=(s1,m2,s2,n2),strides=(0,n2*n,0,n)).reshape(A.shape)
Out[81]: 
array([[35, 60, 35, 60, 35, 60],
       [21, 86, 21, 86, 21, 86],
       [35, 60, 35, 60, 35, 60],
       [21, 86, 21, 86, 21, 86]])

In [82]: A - strided(B,shape=(s1,m2,s2,n2),strides=(0,n2*n,0,n)).reshape(A.shape)
Out[82]: 
array([[ -6,  -7,  -5, -35,  57, -50],
       [-19, -66,  14,   1, -21, -77],
       [ 11, -30, -15,   2,  44,   3],
       [ 23, -77,  57, -53, -15, -46]])

方法2:我們可以將ABreshape4D形狀,其中B具有兩個單例尺寸,當從A 4D版本中減去其元素時,將沿其broadcasted 減去后,我們將重新調整為2D形狀以進行最終輸出。 因此,我們將有一個實現,像這樣-

m1,n1 = A.shape
m2,n2 = B.shape
out = (A.reshape(m1//m2,m2,n1//n2,n2) - B.reshape(1,m2,1,n2)).reshape(m1,n1)

如果A的尺寸是B的尺寸的倍數,則此方法應該起作用:

A - np.tile(B, (int(A.shape[0]/B.shape[0]), int(A.shape[1]/B.shape[1])))

結果:

array([[ 0, -1,  1,  0],
       [-2, -3, -1, -2],
       [ 2,  1,  3,  2],
       [ 0, -1,  1,  0]])

如果不想平鋪,則可以調整A的形狀以提取(2, 2)個塊,並使用廣播減去B:

C = A.reshape(A.shape[0]//2, 2, A.shape[1]//2, 2).swapaxes(1, 2)
C - B
array([[[[ 0, -1],
     [-2, -3]],

    [[ 1,  0],
     [-1, -2]]],


   [[[ 2,  1],
     [ 0, -1]],

    [[ 3,  2],
     [ 1,  0]]]])

然后向后交換軸並重塑形狀:

(C - B).swapaxes(1, 2).reshape(A.shape[0], A.shape[1])

這應該快得多,因為C是A上的視圖,而不是構造的數組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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