Numpy:来自子矩阵的广播

时间:2016-11-14 14:57:51

标签: python numpy matrix

给出两个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:A - B上执行B的广播减法。

我特别想使用广播,因为我正在处理的数组大小非常大(8456,8456)。我希望广播能够提供一个小的性能优化。

我尝试过改造阵列,但没有运气,我很难过。我无法使用Scikit。

4 个答案:

答案 0 :(得分: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 Image' 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]]

答案 1 :(得分: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: A B4D B形状4D A有两个单身从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) 版本中减去其元素reshape时的尺寸。减法后,我们重新形成sessions以获得最终输出。因此,我们将有一个实现,如此 -

 public ActionResult ClickCounter()
        {
            return View();
        }

答案 2 :(得分:1)

如果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]])

答案 3 :(得分: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的视图,而不是构造的数组。