【NumPy】*、np.multiply()、np.matmul()或@、np.dot()的异同

简介:

广播机制

*、np.multiply()、np.matmul() 或 @、np.dot()的异同

In [1]: import numpy as np

1、 尺寸相同的两个1-D array

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

结论:

np.multiply()*:array对应元素相乘

np.matmul()@np.dot():向量点积

备注:在numpy中可以使用@来替代matmul,即:

np.matmul(a, b)
# 可以被替代为:
(a @ b)

下文只考虑np.matmul(a,b)

2、 两个2-D array

对于尺寸不同但符合矩阵乘法规则的两个2-D array:

In [17]: a = np.array([i for i in range(6)]).reshape([3,2])

In [18]: a
Out[18]: 
array([[0, 1],
       [2, 3],
       [4, 5]])

In [19]: b=np.array([[0],[1]])

In [20]: b
Out[20]: 
array([[0],
       [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-D array:

In [29]: a=np.array([[1,2],[3,4]])

In [30]: b=np.array([[0,1],[2,3]])

In [31]: a
Out[31]: 
array([[1, 2],
       [3, 4]])

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

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]])

结论:

np.multiply()*:array对应元素相乘。不满足广播的条件则出错。

np.matmul()@np.dot():矩阵乘法

3、 两个 matrix

对于尺寸不同但符合矩阵乘法规则的两个 matrix:

In [48]: a = np.matrix([i for i in range(6)]).reshape([3,2])
Out[48]: 
matrix([[0, 1],
        [2, 3],
        [4, 5]])

In [49]: b=np.matrix([[0],[1]])
Out[49]: 
matrix([[0],
        [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]])

对于尺寸相同的两个matrix:

In [56]: a=np.matrix([[1,2],[3,4]])

In [57]: b=np.matrix([[0,1],[2,3]])

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

In [59]: b
Out[59]: 
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]])

结论:

np.multiply():matrix对应元素相乘。不满足广播的条件则出错。

*np.matmul()@np.dot():矩阵乘法

4、 np.matmul() vs. np.dot()

上面三种情况np.matmul()和. np.dot()的结果都是相同的,我们来看看它们之间的差别。

考虑2维以上array:
np.multiply()*依然是array对应元素相乘,不满足广播的条件则出错。这里略过相应代码,我们主要来看看np.matmul()np.dot()

In [95]: a = np.array([i for i in range(12)]).reshape([2,2,3])

In [96]: b = np.array([i for i in range(6)]).reshape([1,3,2])

In [97]: a
Out[97]: 
array([[[ 0,  1,  2],
        [ 3,  4,  5]],

       [[ 6,  7,  8],
        [ 9, 10, 11]]])

In [98]: b
Out[98]: 
array([[[0, 1],
        [2, 3],
        [4, 5]]])

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)

In [103]: a = np.array([i for i in range(12)]).reshape([2,2,3])

In [104]: b = np.array([i for i in range(12)]).reshape([2,3,2])

In [105]: a
Out[105]: 
array([[[ 0,  1,  2],
        [ 3,  4,  5]],

       [[ 6,  7,  8],
        [ 9, 10, 11]]])

In [106]: b
Out[106]: 
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5]],

       [[ 6,  7],
        [ 8,  9],
        [10, 11]]])

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)


结论[1]:

np.matmul() 分别把数组的最后两个维度(组成矩阵)视为一个元素,并对其进行广播。
如上文中b.shape:[1,3,2]广播为[2,3,2]再与a相乘。

广播后两个数组matmul 即两个数组对应位置的矩阵相乘。在上面的例子中,两个数组分别由两个$2\times 3$和$3\times 2$的矩阵组成。通过对应位置矩阵进行矩阵乘法,得到结果为两个$2\times 2$的矩阵。

np.dot() 则对第一个数组的最后一个维度(行向量)以及第二个数组的倒数第二个维度(列向量)进行点积。在上面的例子中,a可以看作$2\times 2$个行向量。b可以看作$2\times 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

参考:

[1]https://www.delftstack.com/howto/numpy/numpy-dot-vs-matmul/

相关文章
|
3月前
numpy.random.rand(d0, d1, …, dn)
numpy.random.rand(d0, d1, …, dn)
17 0
|
5月前
np.where()使用详解
1.函数介绍 np.where函数相当于三元表达式的向量版本,能够针对向量作三元操作,有两种使用方法。 np.where(condition, x, y):当满足第一个参数条件时,where返回x,不满足第一个参数的条件时返回y。
62 0
|
11月前
|
Python
【Numpy】深入剖析Numpy.arange()与range()的区别
【Numpy】深入剖析Numpy.arange()与range()的区别
100 0
|
C语言 Python
numpy.zeros(np.zeros)使用方法--python学习笔记31
numpy.zeros(np.zeros)使用方法--python学习笔记31
280 0
|
Python
【Numpy库学习笔记】Numpy中dim、shape和size的理解
【Numpy库学习笔记】Numpy中dim、shape和size的理解
236 0
|
数据可视化 PyTorch 算法框架/工具
np.squeeze 的用法
np.squeeze 的用法
|
机器学习/深度学习 PyTorch 算法框架/工具
Numpy | np.random随机模块的使用介绍
Numpy | np.random随机模块的使用介绍
193 0
Numpy | np.random随机模块的使用介绍
|
算法 定位技术
浅谈P、NP、NP-Complate和NP-Hard问题
时间复杂度 时间复杂度并不是表示一个程序解决问题需要花多少时间,而是当程序所处理的问题规模扩大后,程序需要的时间长度对应增长得有多快。 也就是说,对于某一个程序,其处理某一个特定数据的效率不能衡量该程序的好坏,而应该看当这个数据的规模变大到数百倍后,程序运行时间是否还是一样,或者也跟着慢了数百倍,或者变慢了数万倍。 不管数据有多大,程序处理所花的时间始终是那么多的,我们就说这个程序很好,具O(1)O(1)O(1)的时间复杂度,也称常数级复杂度;