(Python Numpy) 是否存在赋值运算符(例如 *=)起作用但长手版本不起作用的情况?

(Python Numpy) Are there cases where assignment operators (eg. *=) work but the long hand versions don't?

我将两个相同大小的矩阵 A 和 B 逐元素相乘。当我使用以下代码时出现 'shapes not aligned' 错误:

    A = A*B

但是以下代码可以正常工作:

    A *= B

这些有区别吗?是否存在第二个可以工作而第一个不能工作的情况?我真的很困惑,因为我认为他们做了同样的事情。

错误是由于 A 是一个 nd 数组而 B 是 'matrix' 类型。

使用:

A = A * np.asarray(B)

转换矩阵有效。

我还是想知道一个有效而另一个无效的原因!

是的。就地运算符使用不同的 dunders than standard operators. In order to use inplace operators,例如*= 必须为带有参数的实例定义 __imul__ 方法。相反,* 运算符使用实例的 __mul__ 方法。

如果正如您在答案中注意到的那样,一个数组是 np.matrix:

In [52]: A = np.ones((1,3)); B = np.matrix([1,2,3])
In [53]: A
Out[53]: array([[1., 1., 1.]])
In [54]: B
Out[54]: matrix([[1, 2, 3]])

它们的形状相同。但是 * for B 是矩阵乘法。

In [55]: A*B
Traceback (most recent call last):
  File "<ipython-input-55-47896efed660>", line 1, in <module>
    A*B
  File "/usr/local/lib/python3.8/dist-packages/numpy/matrixlib/defmatrix.py", line 224, 
 in __rmul__
    return N.dot(other, self)
  File "<__array_function__ internals>", line 5, in dot
ValueError: shapes (1,3) and (1,3) not aligned: 3 (dim 1) != 1 (dim 0)

请注意,A*B 变为 B.__rmul__(A),后者又被计算为 np.dot(A,B)

dot for (1,3) with (3,1) 产生 (1,1) 内积。还要注意结果是 np.matrix.

In [56]: A*B.T
Out[56]: matrix([[6.]])

*=A's乘法规则中:

In [57]: A *=B
In [58]: A
Out[58]: array([[1., 2., 3.]])

@是矩阵乘法运算符:

In [59]: A@B
Traceback (most recent call last):
  File "<ipython-input-59-5016aafd2858>", line 1, in <module>
    A@B
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)

In [60]: A@B.T
Out[60]: matrix([[14.]])

正在将 B 转换为 np.array:

In [61]: B.A
Out[61]: array([[1, 2, 3]])
In [62]: A@(B.T).A
Out[62]: array([[14.]])

查看 np.matrix 文档。

为什么 A*B 使用 B's 乘法定义而不是 A's?因为matrix的优先级更高:

In [63]: B.__array_priority__
Out[63]: 10.0
In [64]: A.__array_priority__
Out[64]: 0.0

注意当 B 在右边时会发生什么:

In [70]: B *= A
Traceback (most recent call last):
  File "<ipython-input-70-50eabec4c4f6>", line 1, in <module>
    B *= A
  File "/usr/local/lib/python3.8/dist-packages/numpy/matrixlib/defmatrix.py", line 227, in __imul__
    self[:] = self * other
  File "/usr/local/lib/python3.8/dist-packages/numpy/matrixlib/defmatrix.py", line 218, in __mul__
    return N.dot(self, asmatrix(other))
  File "<__array_function__ internals>", line 5, in dot
ValueError: shapes (1,3) and (1,3) not aligned: 3 (dim 1) != 1 (dim 0)

In [71]: B *= A.T
In [72]: B
Out[72]: matrix([[14, 14, 14]])

即使 np.matrix 不是一个因素,A*=... 也会有所不同,因为 A's shape 和 dtype 不能改变。 A=A* 创建一个新数组,它可能具有不同的形状或数据类型。

例如Out[72]是int dtype,就像原来的B一样。 Out[58] 是浮动的,就像原来的 A.


由于优先级的关系,A*B被评估为B.__rmul__(A)。将此代码与 In[55]:

的回溯进行比较
Signature: B.__rmul__(other)
Docstring: Return value*self.
Source:   
    def __rmul__(self, other):
        return N.dot(other, self)