numpy里的乘法函数非常多,容易弄混也容易忘,本文总结一下其中比较常见的乘法函数,便于自己查询记忆。下篇文章再总结一下Pytorch和TensorFlow里常用的乘法函数
目录
np.multiply() 或者 *【array下完全等价,mat/matrix下不同】
常用
np.dot()
功能:
- 向量点积(若处理的是一维数组,则得到的是两数组的内积;标量也是直接相乘)
- 矩阵乘法(若处理的是二维数组/矩阵,则得到的是矩阵积,即:若x是m*n矩阵,y是n*m矩阵,则结果为m*m矩阵)
点积 和 矩阵乘法 的含义见附录
写法: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)
np.multiply() 或者 *【array下完全等价,mat/matrix下不同】
两个数组对应位置进行相乘,参与运算的两个数组的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不同
- 两者行数相同,且其中某个矩阵的列数为1。如:m*n 与 m*1 = m*n
- 两者列数相同,且其中某个矩阵的行数为1。如:m*n 与 1*n = m*n
一句话总结, 这种情况下,数组会自适应按列相乘还是按行相乘
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.multiply() 对比 *
在输入为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.dot()、np.multiply()、* 小结
小结一下:
- np.dot() 无论数据是array还是matrix都表示矩阵相乘
- np.multiply() 无论数据是array或matrix都表示对应位置相乘
- 如果数据类型为array,* 和 np.multiply() 表示对应位置相乘,np.dot() 表示矩阵相乘
- 如果数据类型为matrix,np.multiply() 表示对应位置相乘,* 和 np.dot() 表示矩阵相乘
np.matmul() 或者 @【完全等价】
两个运算的矩阵需要满足矩阵乘法的规则(前一个矩阵的列与后一个矩阵的行相匹配)
写法: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()
目前为止,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() 分别把数组的最后两个维度(组成矩阵)视为一个元素,并对其进行广播
- 如上文中 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可以看作1 × 2个列向量。np.dot() 会将 a的每一个行向量 与 b的全部列向量 进行点积,每一个行向量都能得到一个二维数组,占据结果的后两维。属于同一个二维数组的行向量,得到的结果又合并为一个三维数组。这个三维数组又与其他二维数组的行向量得到的三维数组合并成四维数组
再举个例子:
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少了一维
不常用
以下几个函数不太常用,需要用到的时候查一下,或者写个测试用例看看输出就行
np.prod()
功能:返回数组中所有元素的乘积
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()
作用:计算两个向量的外积,拿第一个向量的元素分别与第二个向量所有元素相乘得到的结果的一行,以此类推
参数:np.outer(x, y)
- x和y都是向量,若输入不是一维的,会被展平
- 输出满足:out[i, j] = x[i] * y[j]
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.matrix、np.mat
np.array 是创建数组,必须自己手动输入数组;np.arange 可以产生一串数字,从而创建数组。使用 reshape 后可以将数组转换为矩阵
- (12, )表示是数组,只有一个[ ]
- (1, 12)是一维矩阵,左右各有两个[ ]
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]])
#生成 <class 'numpy.matrix'> 矩阵
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]])
#生成 <class 'numpy.matrix'> 矩阵
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博客