【Numpy乘法详解(代码示例)】np.multiply()、np.matmul()、np.dot()等
文章目录
1. 介绍
- 星号(*):array对应元素相乘,不满足广播的条件则出错、矩阵乘法。
- np.multiply():array(matrix)对应元素相乘,不满足广播的条件则出错。
- np.matmul():向量点积、矩阵乘法。
- 艾特(@):向量点积、矩阵乘法。注意:在numpy中可以使用@来替代np.matmul,下面不做赘述。
- np.dot():向量点积、矩阵乘法。
2. 代码示例
2.1 一维数组(np.array__1D)
In [2]: a=np.array([1,2])
In [3]: b=np.array([3,4])
In [4]: a*b
Out[4]: array([3, 8])
In [5]: np.multiply(a,b)
Out[5]: array([3, 8])
In [6]: np.matmul(a,b)
Out[6]: 11
In [7]: np.dot(a,b)
Out[7]: 11
In [8]: a@b
Out[8]: 11
2.2 二维(多维)数组(np.array__xD)
多维数组对于np.dot和np.matual会有一些不同,下面2.4中会举例说明。
2.2.1 满足矩阵乘法,但尺寸不同
In [18]: a = np.array([[0, 1],[2, 3],[4, 5]]) # (3, 2)
In [19]: b = np.array([[0],[1]]) # (2, 1)
In [21]: a*b
---------------------------------------------------------------------------
ValueError: operands could not be broadcast together with shapes (3,2) (2,1)
In [22]: np.multiply(a,b)
---------------------------------------------------------------------------
ValueError: operands could not be broadcast together with shapes (3,2) (2,1)
In [23]: np.matmul(a,b)
Out[23]:
array([[1],
[3],
[5]])
In [24]: np.dot(a,b)
Out[24]:
array([[1],
[3],
[5]])
2.2.2 满足矩阵乘法,且尺寸相同
In [29]: a=np.array([[1,2],[3,4]]) # (2, 2)
In [30]: b=np.array([[0,1],[2,3]]) # (2, 2)
In [33]: a*b
Out[33]:
array([[ 0, 2],
[ 6, 12]])
In [34]: np.multiply(a,b)
Out[34]:
array([[ 0, 2],
[ 6, 12]])
In [35]: np.matmul(a,b)
Out[35]:
array([[ 4, 7],
[ 8, 15]])
In [36]: np.dot(a,b)
Out[36]:
array([[ 4, 7],
[ 8, 15]])
2.2.3 不满足矩阵乘法,但尺寸相同
>>> a = np.array([[0, 1],[2, 3],[4, 5]]) #(3, 2)
>>> b = np.array([[0, 1],[2, 3],[4, 5]]) #(3, 2)
>>> a*b
array([[ 0, 1],
[ 4, 9],
[16, 25]])
>>> np.multiply(a,b)
array([[ 0, 1],
[ 4, 9],
[16, 25]])
>>> np.matmul(a,b)
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 2)
>>> np.dot(a, b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<__array_function__ internals>", line 6, in dot
ValueError: shapes (3,2) and (3,2) not aligned: 2 (dim 1) != 3 (dim 0)
2.3 矩阵(np.matrix)
2.3.1 矩阵尺寸不同,但符合矩阵乘法
In [48]: a = np.matrix([[0, 1],
[2, 3],
[4, 5]]) #(3, 2)
In [49]: b=np.matrix([[0],
[1]]) #(2, 1)
# 出现不同!!!!
In [50]: a*b
Out[50]:
matrix([[1],
[3],
[5]])
In [51]: np.multiply(a,b)
---------------------------------------------------------------------------
ValueError: operands could not be broadcast together with shapes (3,2) (2,1)
In [52]: np.matmul(a,b)
Out[52]:
matrix([[1],
[3],
[5]])
In [53]: np.dot(a,b)
Out[53]:
matrix([[1],
[3],
[5]])
2.3.2 矩阵尺寸相同
In [56]: a=np.matrix([[1,2],[3,4]])
In [57]: b=np.matrix([[0,1],[2,3]])
In [60]: a*b # 矩阵乘法
Out[60]:
matrix([[ 4, 7],
[ 8, 15]])
In [61]: np.multiply(a,b) # 点积
Out[61]:
matrix([[ 0, 2],
[ 6, 12]])
In [62]: np.matmul(a,b)
Out[62]:
matrix([[ 4, 7],
[ 8, 15]])
In [63]: np.dot(a,b)
Out[63]:
matrix([[ 4, 7],
[ 8, 15]])
2.4 np.matmul()__vs__np.dot()
上面五种情况np.matmul()和. np.dot()的结果都是相同的,我们来看看它们之间的差别。
差别在于2维以上np.array数组:
np.multiply()和*依然是array对应元素相乘,不满足广播的条件则出错。接下来主要分析np.matmul()和np.dot()。
In [97]: a = np.array([[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 6, 7, 8],
[ 9, 10, 11]]]) # (2, 2, 3)
In [98]: b = np.array([[[0, 1],
[2, 3],
[4, 5]]]) # (1, 3, 2)
In [99]: np.dot(a,b)
Out[99]:
array([[[[10, 13]],
[[28, 40]]],
[[[46, 67]],
[[64, 94]]]])
In [100]: np.dot(a,b).shape
Out[100]: (2, 2, 1, 2)
In [101]: np.matmul(a,b)
Out[101]:
array([[[10, 13],
[28, 40]],
[[46, 67],
[64, 94]]])
In [102]: np.matmul(a,b).shape
Out[102]: (2, 2, 2) # 比dot少了一维!!!!!
In [105]: a = np.array([[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 6, 7, 8],
[ 9, 10, 11]]]) # (2, 2, 3)
In [106]: b = np.array([[[ 0, 1],
[ 2, 3],
[ 4, 5]],
[[ 6, 7],
[ 8, 9],
[10, 11]]]) # (2, 3, 2)
In [107]: np.dot(a,b)
Out[107]:
array([[[[ 10, 13],
[ 28, 31]],
[[ 28, 40],
[100, 112]]],
[[[ 46, 67],
[172, 193]],
[[ 64, 94],
[244, 274]]]])
In [118]: np.dot(a,b).shape
Out[118]: (2, 2, 2, 2)
In [109]: np.matmul(a,b)
Out[109]:
array([[[ 10, 13],
[ 28, 40]],
[[172, 193],
[244, 274]]])
In [110]: np.matmul(a,b).shape
Out[110]: (2, 2, 2) # 比dot少了一维!!!!!
获得结论:
-
np.matmul() 分别把数组的最后两个维度(组成矩阵)视为一个元素,并对其进行广播。
如上文中b.shape:[1,3,2],广播为[2,3,2]再与a相乘。广播后两个数组matmul 即两个数组对应位置的矩阵相乘。在上面的例子中,最终结果分别由两对2 × 3 和 3 × 2 的矩阵乘法得到两个2 × 2矩阵,即2 × 2 × 2。 -
np.dot() 则对第一个数组的最后一个维度(行向量)以及第二个数组的倒数第二个维度(列向量)进行点积。
在上面的例子中,a可以看作2 × 2个行向量。b可以看作2 × 2个列向量。np.dot会将a的每一个行向量与b的全部列向量进行点积,每一个行向量都能得到一个二维数组,占据结果的后两维。属于同一个二维数组的行向量,得到的结果又合并为一个三维数组。这个三维数组又与其他二维数组的行向量得到的三维数组合并成四维数组。
注意:np.matmul() 和np.dot() 还有一个区别是:np.matmul() 无法用于标量与array相乘。
In [113]: a=np.array([1,2,3])
In [114]: np.dot(a, 2)
Out[114]: array([2, 4, 6])
In [115]: np.matmul(a,2)
ValueError: Scalar operands are not allowed, use '*' instead
3. 参考
【1】https://www.delftstack.com/howto/numpy/numpy-dot-vs-matmul/
【2】https://blog.csdn.net/weixin_44378835/article/details/117028708