不使用循环,将矩阵A的每一行从矩阵B的每一行中减去。

6

给定两个数组 A(形状:M X C)和 B(形状:N X C),是否有一种方法可以在不使用循环的情况下从A的每一行中减去B的每一行?最终输出的形状将是(M N X C)。


示例

A = np.array([[  1,   2,   3], 
              [100, 200, 300]])

B = np.array([[  10,   20,   30],
              [1000, 2000, 3000],
              [ -10,  -20,   -2]])

期望的结果(可以有其他形状)(已编辑):
array([[  -9,   -18,   -27],
       [-999, -1998, -2997],
       [  11,    22,     5],
       [  90,   180,   270],
       [-900, -1800, -2700],
       [ 110,   220,   302]])

Shape: 6 X 3

循环太慢了,“outer”会减去每个元素而非每一行。

我编辑了问题以展示期望的结果。 - coolscitist
给定的期望输出与期望输出的描述不匹配。 - Rodrigo de Azevedo
2个回答

9

通过利用broadcasting,可以高效地完成它(而不使用任何循环):

In [28]: (A[:, np.newaxis] - B).reshape(-1, A.shape[1])
Out[28]: 
array([[   -9,   -18,   -27],
       [ -999, -1998, -2997],
       [   11,    22,     5],
       [   90,   180,   270],
       [ -900, -1800, -2700],
       [  110,   220,   302]])

或者,如果想要比broadcasting更快捷的解决方案,我们可以使用numexpr,例如:

In [31]: A_3D = A[:, np.newaxis]
In [32]: import numexpr as ne

# pass the expression for subtraction as a string to `evaluate` function
In [33]: ne.evaluate('A_3D - B').reshape(-1, A.shape[1])
Out[33]: 
array([[   -9,   -18,   -27],
       [ -999, -1998, -2997],
       [   11,    22,     5],
       [   90,   180,   270],
       [ -900, -1800, -2700],
       [  110,   220,   302]], dtype=int64)

另一种效率最低的方法是使用np.repeatnp.tile来匹配两个数组的形状。但请注意,这是效率最低的选项,因为在尝试匹配形状时会进行复制

In [27]: np.repeat(A, B.shape[0], 0) - np.tile(B, (A.shape[0], 1))
Out[27]: 
array([[   -9,   -18,   -27],
       [ -999, -1998, -2997],
       [   11,    22,     5],
       [   90,   180,   270],
       [ -900, -1800, -2700],
       [  110,   220,   302]])

1
我会颠倒你的建议顺序 - 在这里广播是规范的方式。手动重复和平铺应该保留在需要它们时使用。 - DSM
1
谢谢。我肯定更喜欢广播方法。 - coolscitist
1
谢谢。我之前不熟悉numexpr,会尝试使用它。 - coolscitist
@kmario23,这对于大矩阵来说会产生问题。我有一个A矩阵(180000,3)和一个B矩阵(50000,3)..都是双精度浮点数。当我尝试计算A [:,np.newaxis] - B时,我遇到了MemoryError。请问有什么建议可以帮助解决这个问题吗? 循环需要1100秒。 - Mubeen Shahid
1
@MubeenShahid 是的,这样巨大的数组大小可能会有问题。根据您提到的大小,至少需要101GB的RAM(即(180000* 50000* 3 * 4)/1024/1024/1024),假设没有其他进程使用任何RAM,当然这是不可能的。为了规避这个问题,numpy.memmap可能会有所帮助,但我自己还没有尝试过。您也可以发布一个新的问题,以收集更多来自他人的意见... - kmario23

1

使用Kronecker productnumpy.kron):

>>> import numpy as np
>>> A = np.array([[  1,   2,   3], 
...               [100, 200, 300]])
>>> B = np.array([[  10,   20,   30],
...               [1000, 2000, 3000],
...               [ -10,  -20,   -2]])
>>> (m,c) = A.shape
>>> (n,c) = B.shape
>>> np.kron(A,np.ones((n,1))) - np.kron(np.ones((m,1)),B)
array([[   -9.,   -18.,   -27.],
       [ -999., -1998., -2997.],
       [   11.,    22.,     5.],
       [   90.,   180.,   270.],
       [ -900., -1800., -2700.],
       [  110.,   220.,   302.]])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接