Lumen

Lumen

Eager to know more, about the world, about the intelligence, and about myself.
github

numpy数组是行向量还是列向量

tldr: 它是行向量,在进行矩阵乘法时会自动扩展 / 转换为适当的维度。

我一直被 “numpy 数组是行向量还是列向量” 的问题困扰。我知道对于一维向量,它既不是行向量也不是列向量,正如其他人所指出的那样。但如果没有对这个问题的正确理解,每次我尝试想象在实现自己的代数时会发生什么,我都没有足够的信心,这种不自信真的很烦人,因为我总是担心自己可能写错了什么。

我将这个问题视为,当一个二维 numpy 数组(即矩阵)和一个一维 numpy 数组相乘时,这个二维 numpy 数组的哪个维度进行矩阵乘法。这并不简单,因为理论上两边都可以工作,但它们产生的结果完全不同。因此,今天我使用简单的 python 交互式 shell 一次性解决这个问题。

简单实验#

定义一个矩阵 m

>>> m = np.array([[1,2,3],[2,3,4],[3,4,5]])
>>> m
array([[1, 2, 3],
       [2, 3, 4],
       [3, 4, 5]])

定义一个向量 v

>>> v = np.array([1,2,3])
>>> v
array([1, 2, 3])

进行逐元素相乘:

>>> m * v
array([[ 1,  4,  9],
       [ 2,  6, 12],
       [ 3,  8, 15]])

这很直观:两个组件中所有最小的元素(一个三维数组)逐元素相乘。

直接进行矩阵乘法:

>>> m @ v
array([14, 20, 26])
>>> v @ m
array([14, 20, 26])

有趣的是,在两个方向上它们的结果是相同的。因为交换律不适用于矩阵乘法,不仅 m @ vv @ m 不应该有相同的输出,而且至少一边不应该是有效操作。因此,结果表明 在 numpy 操作 @中发生了隐式转换

这种隐式转换既聪明又愚蠢 —— 聪明在于它使解释器推断形状,以便 它们可以猜测你想写什么。但这也意味着如果你在代码中犯了逻辑错误,并恰好被正确推断,解释器将继续执行而不会抛出错误,即使你在进行错误的计算也不会给你适当的警告。这也是让我对底层发生的事情缺乏信心的罪魁祸首。

消除隐式转换#

因此,为了消除这种模糊性,我们手动将向量广播到相同的二维数组并查看会发生什么。正如预期的那样,这次我们可以看到它们是如何被不同对待的:

>>> v[None,:]
array([[1, 2, 3]])

# 左乘这个向量
>>> v[None,:] @ m
array([[14, 20, 26]])

# 右乘这个向量
>>> m @ v[None,:]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 1 is different from 3)

另一边的操作也是一样:

>>> v[:,None]
array([[1],
       [2],
       [3]])
>>> m @ v[:,None]
array([[14],
       [20],
       [26]])
>>> v[:, None] @ m
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 3 is different from 1)

结论#

所以最后答案很明确,一个单一的向量在矩阵中本质上被视为行向量。无需担心,numpy 的世界现在在我脑海中是完美有序的;)。我希望这种隐式转换从一开始就没有实现,这样我可能会通过几个运行时错误更早地了解到这个事实。

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。