numpy里的乘法函数非常多,容易弄混也容易忘,本文总结一下其中比较常见的乘法函数,便于自己查询记忆。下篇文章再总结一下Pytorch和TensorFlow里常用的乘法函数
目录
np.multiply() 或者 *【array下完全等价,mat/matrix下不同】
功能:
点积 和 矩阵乘法 的含义见附录
写法:x.dot(y) 等价于 np.dot(x, y)
- import numpy as np
-
- # 向量点积
- x=np.array([0,1,2,3,4]) # 等价于x=np.arange(0,5)
- y=x[::-1] # [4,3,2,1,0]
- print(np.dot(x,y)) # 10
-
- # 矩阵乘法
- x=np.arange(0,6).reshape(2,3)
- y=np.random.randint(0,10,size=(3,2))
- print(np.dot(x,y)) # (2,2)
两种特殊情况:
(1)高维数组
- a = np.arange(6).reshape(1, 2, 3)
- b = np.arange(6).reshape(2, 3, 1)
-
- a
- >>>
- array([[[0, 1, 2],
- [3, 4, 5]]])
- b
- >>>
- array([[[0],
- [1],
- [2]],
-
- [[3],
- [4],
- [5]]])
-
- # 计算n维数组数组的点积
- np.dot(a, b)
- >>>
- array([[[[5],
- [14]],
-
- [[14],
- [50]]]]) # (1, 2, 2, 1)
(2)x为向量,y为矩阵
- import numpy as np
-
- x=np.arange(0,5) # shape为(5,)
- y=np.random.randint(0,10,size=(5,1))
- print(x)
- print(y)
- print(np.dot(x,y)) # 注意结果为[35],而不是35
扩展一下:
- import numpy as np
-
- a = np.arange(6).reshape(1, 2, 3)
- '''
- [[[0 1 2]
- [3 4 5]]]
- '''
- b = np.arange(0,3) # [0 1 2] shape为(3,)
- print(np.dot(a,b)) # [[ 5 14]] shape为(1, 2)
两个数组对应位置进行相乘,参与运算的两个数组的shape、以及结果的shape均一致
写法:np.multiply(x, y) 等价于 x*y(在输入为 np.array 类型时完全等价,但在输入为 np.mat 或np.matrix 类型时出现不同,后面会对比)
- import numpy as np
-
- # 两个向量
- x=np.array([0,1,2,3,4]) # 等价于x=np.arange(0,5)
- y=x[::-1] # [4,3,2,1,0]
- print(np.multiply(x,y)) # [0 3 4 3 0]
-
- # 两个矩阵
- x=np.arange(0,6).reshape(2,3)
- y=np.random.randint(0,10,size=(2,3))
- print(x)
- print(y)
- print(np.multiply(x,y)) # (2,3)
两种特殊情况:
(1)x为向量,y为矩阵。如:x为(m, ),y为(m,1),结果为(m,m)
- import numpy as np
-
- x=np.arange(0,5) # shape为(5,)
- y=np.random.randint(0,10,size=(5,1))
- print(x)
- print(y)
- print(np.multiply(x,y)) # 会自动广播
(2)x和y都为矩阵但shape不同
一句话总结, 这种情况下,数组会自适应按列相乘还是按行相乘
- import numpy as np
-
- x=np.random.randint(0,10,size=(5,2))
- y=np.random.randint(0,10,size=(5,1))
- print(x)
- print(y)
- print(np.multiply(x,y)) # 5*2
在输入为np.array类型时,两者的功能都是元素对位相乘
在输入为np.mat或np.matrix类型时,np.multiply()仍是元素对位相乘,而 * 变为了矩阵乘法
np.array、np.matrix、np.mat 的区别见附录
- 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)
小结一下:
两个运算的矩阵需要满足矩阵乘法的规则(前一个矩阵的列与后一个矩阵的行相匹配)
写法:np.matmul(x, y) 等价于 x@y (两者完全等价)
- import numpy as np
-
- # 两个向量
- x=np.array([0,1,2,3,4]) # 等价于x=np.arange(0,5)
- y=x[::-1] # [4,3,2,1,0]
- print(np.matmul(x,y)) # 10
-
- # 两个矩阵
- x=np.arange(0,6).reshape(2,3)
- y=np.random.randint(0,10,size=(3,2))
- print(x)
- print(y)
- print(np.matmul(x,y)) # (2,2)
一种特殊情况:x为向量,y为矩阵
- import numpy as np
-
- x=np.arange(0,5) # shape为(5,)
- y=np.random.randint(0,10,size=(5,1))
- print(x)
- print(y)
- print(np.matmul(x,y)) # 注意结果为[43],而不是43
目前为止,np.matmul() 和 np.dot() 的功能一模一样,那么两者的区别在哪呢?
差别有二:(1)np.matmul() 中禁止矩阵与标量的乘法;(2)在于2维以上的np.array
(1)np.matmul() 无法用于标量与array相乘:
- In [113]: a=np.array([1,2,3])
-
- In [114]: np.dot(a, 2) # np.multiply(a,2) 和 a*2 结果一样
- Out[114]: array([2, 4, 6])
-
- In [115]: np.matmul(a,2)
- ValueError: Scalar operands are not allowed, use '*' instead
小结一下,np.dot()、np.multiply()、* 都能用于数组和标量相乘,np.matmul() 或 @ 不能
(2)2维以上的np.array:
执行np.matmul(x, y)时,若x的最后一个维度与y的倒数第二个维度不同,则报错。因为它是把数组的最后两个维度(组成矩阵)视为一个元素
- 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]]]]) # (2, 2, 1, 2)
-
-
- In [101]: np.matmul(a,b)
- Out[101]:
- array([[[10, 13],
- [28, 40]],
-
- [[46, 67],
- [64, 94]]]) # (2, 2, 2) 比dot少了一维
np.matmul() 分别把数组的最后两个维度(组成矩阵)视为一个元素,并对其进行广播
np.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]]]]) # (2, 2, 2, 2)
-
- In [109]: np.matmul(a,b)
- Out[109]:
- array([[[ 10, 13],
- [ 28, 40]],
-
- [[172, 193],
- [244, 274]]]) # (2, 2, 2) 比dot少了一维
以下几个函数不太常用,需要用到的时候查一下,或者写个测试用例看看输出就行
功能:返回数组中所有元素的乘积
- import numpy as np
-
- arr = np.array([1, 2, 3, 4])
- result = np.prod(arr)
- print(result) # 输出 24,即 1*2*3*4 的结果
也可以沿着指定的轴计算乘积。通过设置axis参数,可以指定沿着哪个轴进行乘积计算
- arr = np.array([[1, 2], [3, 4]])
- result = np.prod(arr, axis=0) # axis=0是对每一列操作
- print(result) # 输出 [3 8],即 1*3 和 2*4 的结果
np.prod() 还可以接受一个可选参数dtype,用于指定计算结果的数据类型
作用:计算两个向量的外积,拿第一个向量的元素分别与第二个向量所有元素相乘得到的结果的一行,以此类推
参数:np.outer(x, y)
- import numpy as np
-
- # 数字
- lr = np.outer(np.ones((5,)),np.linspace(-2,2,5))
- lr
- >>>
- array([[-2., -1., 0., 1., 2.],
- [-2., -1., 0., 1., 2.],
- [-2., -1., 0., 1., 2.],
- [-2., -1., 0., 1., 2.],
- [-2., -1., 0., 1., 2.]])
- 其中
- np.ones((5,)) # [1. 1. 1. 1. 1.]
- np.linspace(-2,2,5) # [-2. -1. 0. 1. 2.]
-
- # 数字加文本
- im = np.outer(1j*np.linspace(2,-2,5),np.ones((5,)))
- im
- >>>
- array([[0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j],
- [0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j],
- [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
- [0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j],
- [0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j]])
- 其中
- 1j*np.linspace(2,-2,5) # [ 0.+2.j, 0.+1.j, 0.+0.j, -0.-1.j, -0.-2.j]
-
- grid = lr + im
- grid
- >>>
- array([[-2.+2.j, -1.+2.j, 0.+2.j, 1.+2.j, 2.+2.j],
- [-2.+1.j, -1.+1.j, 0.+1.j, 1.+1.j, 2.+1.j],
- [-2.+0.j, -1.+0.j, 0.+0.j, 1.+0.j, 2.+0.j],
- [-2.-1.j, -1.-1.j, 0.-1.j, 1.-1.j, 2.-1.j],
- [-2.-2.j, -1.-2.j, 0.-2.j, 1.-2.j, 2.-2.j]])
-
- # 文本
- np.outer(np.array(['a','b','c']), [1,2,3]) # 这样写会报错
-
- # 下面的写法才正确
- x = np.array(['a','b','c'], dtype=object)
- np.outer(x, [1,2,3])
- >>>
- [['a' 'aa' 'aaa']
- ['b' 'bb' 'bbb']
- ['c' 'cc' 'ccc']]
特殊情况,若有一个输入为标量:
- np.outer(2, [1,2,3]) # [[2 4 6]]
-
- # np.outer([2], [1,2,3])的结果也是一样的
(1)点积:
(2)矩阵乘法:
np.array 是创建数组,必须自己手动输入数组;np.arange 可以产生一串数字,从而创建数组。使用 reshape 后可以将数组转换为矩阵
np.matrix 可以使二维数组变为二维矩阵,使数组变为一维矩阵
- a = np.arange(12)
- print(a.shape) #(12,)
- #[ 0 1 2 3 4 5 6 7 8 9 10 11]
-
- a = np.matrix(a)
- print(a.shape) #(1, 12)
- #[[ 0 1 2 3 4 5 6 7 8 9 10 11]]
-
- c = np.matrix([[1,2,3,4,5,6],[7,8,9,10,11,12]], dtype=int)
- print(c)
- '''
- [[ 1 2 3 4 5 6]
- [ 7 8 9 10 11 12]]
- '''
np.mat 也能使数组变为矩阵,与 np.matrix 的区别在于:
使用np.mat后,如果对原数组进行改变,矩阵也会相应发生变化
- #创建ndarray二维数组
- x = np.array([[1, 2], [3, 4]])
-
- #生成
矩阵 - m = np.mat(x)
-
- #打印 m 矩阵
- print(m)
- '''
- [[1 2]
- [3 4]]
- '''
-
- x[0,0] = 0
- print(m)
- '''
- [[0 2]
- [3 4]]
- '''
但使用np.matrix后,如果对原数组进行改变,矩阵不会相应发生变化
- #创建ndarray二维数组
- x = np.array([[1, 2], [3, 4]])
-
- #生成
矩阵 - m = np.matrix(x)
-
- #打印 m 矩阵
- print(m)
- '''
- [[1 2]
- [3 4]]
- '''
-
- x[0,0] = 0
- print(m)
- '''
- [[1 2]
- [3 4]]
- '''
【Numpy乘法详解】np.multiply()、np.matmul()、np.dot()等-CSDN博客
numpy——np.array、np.matrix、np.mat的区别及(*)、np.multiply、np.dot乘法的区别_np.mat * 与np.dot()-CSDN博客