2016-11-14 79 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)