2016-11-14 68 views
2

給定兩個二維數組:numpy的:從廣播子矩陣

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不適用於我使用。

+1

預期輸出是什麼? – Whud

+0

這是可能的只使用重塑和軸交換 –

+0

@ P.Camilleri事實證明,我們可以只使用重塑:) – Divakar

回答

2

您可以通過它平鋪在兩個維度展開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很大的開銷。

另外,您可以view A in blocks使用Scikit圖像的skimage.util.view_as_blocks和修改到位

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]] 
+0

是否必須使用平鋪?我一直希望使用廣播的性能優勢。我也無法使用scikit。 – user1658296

+0

你不能只是'安裝scikit-image'嗎?或者,您可以使用[此功能,也可以滑動窗口](https://gist.github.com/nils-werner/9d321441006b112a4b116a8387c2280c)。 –

1

這應該工作,如果A有多個的dimentions 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]]) 
0

如果你不想瓷磚,可以重塑提取(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上的視圖,而不是構造數組,因此這應該快得多。

2

方法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:我們就可以reshapeAB4D形狀,其中B具有兩個單獨尺寸,沿着該單元尺寸,當從4D版本A版本中減去時,其元素將爲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)