NumPy矩阵减法困惑

10

我关于意外执行的两个numpy矩阵操作结果有一个问题(后来已修正)。

假设我有一个列向量 A = [1,2,3],和一个行向量 B = [1,1,1]。据我所知,没有正确的数学方法可以“减去”这两个向量,也就是说这应该是一种未定义的操作。然而,当我这样做时,我得到:

>>> matrix([[0, 1, 2],
            [0, 1, 2],
            [0, 1, 2]])

我认为这可能是某种广播操作,但这仍然让我有点困扰。numpy.matrix对象不应该只包含数学上有效的矩阵运算吗?

任何帮助都将不胜感激!

谢谢!


很有趣。 - Ivan
谷歌“numpy广播” - user1149913
2
@user1149913 我认为问题不在于广播的工作原理,而在于为什么允许一行与列向量相加/相减?同时,请记住np.matrixnp.ndarray的广播规则有很大不同。 - askewchan
3
matrixndarray的子类,它们遵循完全相同的广播规则。主要区别在于__getitem__方法确保始终保留2D对象和__mul__使用.dot而不是np.multiply源代码是纯Python,非常易于理解。 - Jaime
1
使用 np.matrix 被反对的部分原因是由于其不一致的行为。如果您使用的是1D的ndarray,则不会意外获得2D数组。广播是一个在np.ndarray中定义良好的操作,即使对于其matrix子类也适用相同的规则,即使它与“数学矩阵”所期望的不同。 - jorgeca
显示剩余7条评论
2个回答

2

A和B正在一起广播:

A = np.matrix([[1],[2],[3]])
#a 3x1 vector
#1
#2
#3

B = np.matrix([[1,1,1]])
#a 1x3 vector
#1 1 1

A-B
#a 3x3 vector
#0 0 0
#1 1 1
#2 2 2

在其大小为1的维度(列)上,A被广播到

#1 1 1
#2 2 2
#3 3 3

B被沿着其大小为1的维度(行)广播到

#1 1 1
#1 1 1
#1 1 1

然后按照通常的方式计算两个3x3矩阵的A-B。

如果你想知道为什么它不报错而是这样做,那是因为np.matrix继承自np.array。 np.matrix覆盖了乘法,但没有覆盖加法和减法,因此它使用基于np.array的操作,在维度允许的情况下进行广播。


1
但是你必须小心谁在使用它。数学家和物理学家不一定知道这一点(尽管快速谷歌搜索可以告诉你),他们会认为这应该返回一个错误,而实际上并不是。在我看来,np.matrix也应该覆盖加法和减法。毕竟我们谈论的是一个数学库。 - astromax
3
我同意 astromax 的观点。在处理矩阵对象时,我认为最好默认抛出错误或异常,而不是执行意外的操作。Matlab 在这方面做得很好。 - kith

1
我无法真正解释这个理由,因为我经常使用 np.matrix 而不是 np.array 来避免这种情况。感谢 @Jaime 在上面的评论中提供的链接,清楚地表明 np.matrix 只是一个从 np.ndarray 派生出来的子类,其中重新定义了中缀运算,在线性代数中有适当的答案。在没有适当答案的情况下,它会回退到具有 ndim = 2np.ndarray 规则。
看起来加法遵循矩阵乘法规则,其中从 A 中选择哪些元素与 B 中的哪些元素配对:
In [1]: import numpy as np
In [2]: A = np.matrix([1,2,3]).T
In [3]: B = np.matrix([1,1,1])

In [4]: A
Out[4]: 
matrix([[1],
        [2],
        [3]])

In [5]: B
Out[5]: matrix([[1, 1, 1]])

In [6]: A+B
Out[6]: 
matrix([[2, 2, 2],
        [3, 3, 3],
        [4, 4, 4]])

In [7]: A*B
Out[7]: 
matrix([[1, 1, 1],
        [2, 2, 2],
        [3, 3, 3]])

这是使用 np.array 时得到的相同行为:
In [9]: a = np.arange(3)[...,None]

In [10]: b = np.arange(3)

In [11]: a
Out[11]: 
array([[0],
       [1],
       [2]])

In [12]: b
Out[12]: array([0, 1, 2])

In [13]: a+b
Out[13]: 
array([[0, 1, 2],
       [1, 2, 3],
       [2, 3, 4]])

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