在科学计算中,我经常想像做向量乘法
a x b^T
a 和b 是行向量,b^T 是向量的转置。因此,如果 a 和 b 的形状为 [n, 1] 和 [m, 1],则结果矩阵的形状为 [n, m]
在 numpy 中是否有一种好的、直接的方法来写这个乘法?
示例:
a = np.array([1,2,3])
b = np.array([4,5,6,7])
手动添加轴是可行的:
a[:,np.newaxis] @ b[np.newaxis,:]
并给出正确的结果:
[[ 4 5 6 7]
[ 8 10 12 14]
[12 15 18 21]]
爱因斯坦符号是另一种方式,但仍然有些奇怪。
np.einsum('a,b->ab', a,b)
我希望工作,但不工作,是以下内容:
a @ b.T
还有其他方法吗?
最佳答案
在 MATLAB 中矩阵乘法是常态,使用 *
。逐元素乘法使用 .*
运算符。矩阵也至少是二维的。
在 numpy
中,逐元素乘法使用 *
。矩阵乘法使用 np.dot
(或其方法)完成,最近使用 @
运算符 (np.matmul
)。 numpy
添加了广播,这为元素乘法提供了更多的表现力。
使用形状为 (3,) 和 (4,) 的 2 个示例数组,可以选择制作 (3,4) 外积
https://en.wikipedia.org/wiki/Outer_product包括:
np.outer(a,b)
np.einsum('i,j->ij, a, b) # matching einstein index notation
a[:,None] * b # the most idiomatic numpy expression
这最后一个工作是因为广播。 a[:, None]
,如 a.reshape(-1,1)
将 (3,) 数组转换为 (3,1)。 b[None, :]
将 (4,) 转换为 (1,4)。但是广播可以自动(并且明确地)执行此升级。
(3,1) * (4,) => (3,1) * (1,4) => (3,4)
广播不适用于 np.dot
。所以我们需要
a[:, None].dot(b[None, :]) # (3,1) dot with (1,4)
dot
的关键是 a
的最后一个 dim 与 b
的倒数第二个配对。 (np.dot
也适用于 2 个匹配的一维数组,执行传统的向量点积)。
@
(matmul
) 引入了一个类似于 dot
的运算符,至少在 2d with 2d 的情况下是这样。对于更高维的数组,它们的工作方式不同。
a[:,None].dot(b[None,:])
np.dot(a[:,None], b[None,:])
a[:,None] @ b[None,:]
a[:,None] @ b[:,None].T
和 reshape
等价物都创建了所需的 (3,4) 数组。
np.tensordot
可以处理其他维度组合,但它通过 reshape 和转置输入来工作,因此最终它可以将它们传递给 dot
。然后它将结果转换回所需的形状。
Quick time 测试表明 np.dot
版本往往是最快的 - 因为它们将操作委托(delegate)给快速 BLAS 之类的库。对于其他版本,委托(delegate)有点间接,或者他们使用 numpy 的
自己的编译代码。
关于numpy - 在 Numpy 中编写向量矩阵乘积的紧凑自然方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50352935/