numpy - 在 Numpy 中编写向量矩阵乘积的紧凑自然方式

标签 numpy vector matrix-multiplication

在科学计算中,我经常想像做向量乘法

a x b^T

ab 是行向量,b^T 是向量的转置。因此,如果 ab 的形状为 [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/

相关文章:

python - 在极限矩阵上执行二重积分

arrays - 将元胞数组中的 double 插入 MATLAB 中的向量

css - 组合 CSS 矩阵

c - 自定义角度的旋转点矩阵

python - 如果它出现在纯 numpy 中的另一个数组中,则有效地删除数组的每一行

python - 将 numpy 字符串数组转换为 int 数组

python - Numpy 多阶段容器构建——Alpine

c++ - 字符串 vector ,每个字符串的长度和 C++ 中的 strlen

c++ - 原子地 std::vector::push_back() 并返回索引

performance - 如何解释矩阵乘法 GFLOP/s 中的这种差异?