NumPy 线性代数
NumPy 提供了线性代数函数库 linalg,该库包含了线性代数所需的所有功能,可以看看下面的说明:
函数 | 描述 |
---|---|
dot |
两个数组的点积,即元素对应相乘。 |
vdot |
两个向量的点积 |
inner |
两个数组的内积 |
matmul |
两个数组的矩阵积 |
determinant |
数组的行列式 |
solve |
求解线性矩阵方程 |
inv |
计算矩阵的乘法逆矩阵 |
1、numpy.dot()
numpy.dot() 对于两个一维的数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为内积);对于二维数组,计算的是两个数组的矩阵乘积;对于多维数组,它的通用计算公式如下,即结果数组中的每个元素都是:数组a的最后一维上的所有元素与数组b的倒数第二位上的所有元素的乘积和: dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])。
1 numpy.dot(a, b, out=None)
参数说明:
- a : ndarray 数组
- b : ndarray 数组
- out : ndarray, 可选,用来保存dot()的计算结果
实例:
1 import numpy as np 2 # 对于两个一维的数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为内积) 3 x = np.arange(1, 5) 4 y = np.arange(2, 6) 5 print('x: ', x) 6 print('y: ', y) 7 print('a·b=', np.dot(x, y)) 8 #对于二维数组,计算的是两个数组的矩阵乘积 9 a = np.matrix([[1, 2]]) 10 b = np.matrix('2, 3;4, 5') 11 print('a: ', a) 12 print('b: ', b) 13 print(np.dot(a, b))
执行结果:
x: [1 2 3 4] y: [2 3 4 5] a·b= 40 a: [[1 2]] b: [[2 3] [4 5]] [[10 13]]
2、numpy.vdot()
numpy.vdot() 函数是两个向量的点积。 如果第一个参数是复数,那么它的共轭复数会用于计算。 如果参数是多维数组,它会被展开
1 import numpy as np 2 a = np.array([[1, 2], [3, 4]]) 3 b = np.array([[11, 12], [13, 14]]) 4 print('a:{} b:{}'.format(a, b)) 5 # vdot 将数组展开计算内积 6 print(np.vdot(a, b))
执行结果:130
计算式:
1*11 + 2*12 + 3*13 + 4*14 = 130
3、numpy.inner()
numpy.inner() 函数返回一维数组的向量内积。对于更高的维度,它返回最后一个轴上的和的乘积
1 import numpy as np 2 a = np.array([[1, 2], [3, 4]]) 3 print('数组 a:') 4 print(a) 5 b = np.array([[11, 12], [13, 14]]) 6 print('数组 b:') 7 print(b) 8 print('内积:') 9 print(np.inner(a, b))
执行结果:
数组 a: [[1 2] [3 4]] 数组 b: [[11 12] [13 14]] 内积: [[35 41] [81 95]]
内积计算式为:
1*11+2*12, 1*13+2*14
3*11+4*12, 3*13+4*14
4、numpy.matmul
numpy.matmul 函数返回两个数组的矩阵乘积。 虽然它返回二维数组的正常乘积,但如果任一参数的维数大于2,则将其视为存在于最后两个索引的矩阵的栈,并进行相应广播。
另一方面,如果任一参数是一维数组,则通过在其维度上附加 1 来将其提升为矩阵,并在乘法之后被去除。
对于二维数组,它就是矩阵乘法:
1 import numpy as np 2 # 对于二维数组,它就是矩阵乘法 3 a = np.matrix([[1, 0], [0, 1]]) 4 b = np.matrix([[4, 1], [2, 2]]) 5 print('a: {} b: {}'.format(a, b)) 6 print('a·b=', np.matmul(a, b))
执行结果:
a: [[1 0] [0 1]] b: [[4 1] [2 2]] a·b= [[4 1] [2 2]]
二维和一维运算:
1 import numpy.matlib 2 import numpy as np 3 4 a = [[1,0],[0,1]] 5 b = [1,2] 6 print (np.matmul(a,b)) 7 print (np.matmul(b,a))
执行结果:
[1 2]
[1 2]
维度大于二的数组 :
1 import numpy as np 2 3 a = np.arange(8).reshape(2,2,2) 4 b = np.arange(4).reshape(2,2) 5 print (np.matmul(a,b))
执行结果:
[[[ 2 3] [ 6 11]] [[10 19] [14 27]]]、
6、numpy linalg模块
numpy.linalg模块包含线性代数的函数。使用这个模块,可以计算逆矩阵、求特征值、解线性方程组以及求解行列式等
6.1 numpy.linalg.inv()
numpy.linalg.inv() 函数计算矩阵的乘法逆矩阵。
逆矩阵(inverse matrix):设A是数域上的一个n阶矩阵,若在相同数域上存在另一个n阶矩阵B,使得: AB=BA=E ,则我们称B是A的逆矩阵,而A则被称为可逆矩阵。注:E为单位矩阵。
1 import numpy as np 2 A = np.matrix('0, 1, 2;1, 0, 3;4, -3, 8') 3 print('A=', A) 4 # 使用inv函数计算逆矩阵 5 A_inv = np.linalg.inv(A) 6 print('矩阵A的逆矩阵: ', A_inv) 7 # 检查原矩阵和求得的逆矩阵相乘的结果为单位矩阵 8 print('A·A_inv= ', A*A_inv)
执行结果:
A= [[ 0 1 2] [ 1 0 3] [ 4 -3 8]] 矩阵A的逆矩阵: [[-4.5 7. -1.5] [-2. 4. -1. ] [ 1.5 -2. 0.5]] A·A_inv= [[1. 0. 0.] [0. 1. 0.] [0. 0. 1.]]
# 注:矩阵必须是方阵且可逆,否则会抛出LinAlgError异常
6.2 numpy.linalg.solve()
numpy.linalg中的函数solve可以求解形如 Ax = b 的线性方程组,其中 A 为矩阵,b 为一维或二维的数组,x 是未知变量
1 import numpy as np 2 #创建矩阵和数组 3 A = np.matrix([[1, 1, 1], 4 [4, 2, -5], 5 [2, 8, 7]]) 6 b = np.array([6, -4, 27]) 7 # 求解Ax=b的解 8 x = np.linalg.solve(A, b) 9 print('方程组解为: ', x) 10 # 验证 11 print(np.dot(A, x))
执行结果:
方程组解为: [ 2.97727273 -0.11363636 3.13636364] [[ 6. -4. 27.]]
6.3 特征值和特征向量
# 特征值(eigenvalue)即方程 Ax = ax 的根,是一个标量。其中,A 是一个二维矩阵,x 是一个一维向量。特征向量(eigenvector)是关于特征值的向量
numpy.linalg模块中,eigvals函数可以计算矩阵的特征值,而eig函数可以返回一个包含特征值和对应的特征向量的元组
1 import numpy as np 2 # 创建一个矩阵 3 A = np.mat("3 -2;1 0") 4 5 print('调用eigvals函数求解特征值:') 6 a = np.linalg.eigvals(A) 7 print(a) 8 print('使用eig函数求解特征值和特征向量 (该函数将返回一个元组,按列排放着特征值和对应的特征向量, 9 其中第一列为特征值,第二列为特征向量)') 10 a1, a2 = np.linalg.eig(A) 11 print(a1) 12 print(a2) 13 print('使用dot函数验证求得的解是否正确:') 14 15 for i in range(len(a1)): 16 print("left:", np.dot(A, a2[:, i])) 17 print("right:", a1[i] * a2[:, i])
执行结果:
调用eigvals函数求解特征值: [2. 1.] 使用eig函数求解特征值和特征向量 (该函数将返回一个元组,按列排放着特征值和对应的特征向量,其中第一列为特征值,第二列为特征向量) [2. 1.] [[0.89442719 0.70710678] [0.4472136 0.70710678]] 使用dot函数验证求得的解是否正确: left: [[1.78885438] [0.89442719]] right: [[1.78885438] [0.89442719]] left: [[0.70710678] [0.70710678]] right: [[0.70710678] [0.70710678]]
6.4、numpy.linalg.det()
numpy.linalg.det() 函数计算输入矩阵的行列式。
行列式在线性代数中是非常有用的值。 它从方阵的对角元素计算。 对于 2×2 矩阵,它是左上和右下元素的乘积与其他两个的乘积的差。
换句话说,对于矩阵[[a,b],[c,d]],行列式计算为 ad-bc。 较大的方阵被认为是 2×2 矩阵的组合。
1 import numpy as np
2 a = np.array([[1,2], [3,4]])
3
4 print (np.linalg.det(a))
输出结果为:-2.0000000000000004
6.5.奇异值分解
# SVD(Singular Value Decomposition,奇异值分解)是一种因子分解运算,将一个矩阵分解为3个矩阵的乘积
# numpy.linalg模块中的svd函数可以对矩阵进行奇异值分解。该函数返回3个矩阵——U、Sigma和V,其中U和V是正交矩阵,Sigma包含输入矩阵的奇异值。
1 import numpy as np 2 # 创建矩阵 3 D = np.mat("4 11 14;8 7 -2") 4 # 使用svd函数分解矩阵 5 U, Sigma, V = np.linalg.svd(D, full_matrices=False) 6 print('U: ', U) 7 print('Sigma ', Sigma) 8 print('V: ', V) 9 # 使用diag函数生成完整的奇异值矩阵。将分解出的3个矩阵相乘 10 print('diag(Sigma): ', np.diag(Sigma)) 11 print(U * np.diag(Sigma) * V)
执行结果:
U: [[-0.9486833 -0.31622777] [-0.31622777 0.9486833 ]] Sigma [18.97366596 9.48683298] V: [[-0.33333333 -0.66666667 -0.66666667] [ 0.66666667 0.33333333 -0.66666667]] diag(Sigma): [[18.97366596 0. ] [ 0. 9.48683298]] [[ 4. 11. 14.] [ 8. 7. -2.]]
6.6 广义逆矩阵
1 import numpy as np 2 # 创建一个矩阵 3 E = np.mat("4 11 14;8 7 -2") 4 print('使用pinv函数计算广义逆矩阵:') 5 pseudoinv = np.linalg.pinv(E) 6 print(pseudoinv) 7 print('将原矩阵和得到的广义逆矩阵相乘:') 8 print(E * pseudoinv)
执行结果:
使用pinv函数计算广义逆矩阵: [[-0.00555556 0.07222222] [ 0.02222222 0.04444444] [ 0.05555556 -0.05555556]] 将原矩阵和得到的广义逆矩阵相乘: [[ 1.00000000e+00 -9.29811783e-16] [-1.66533454e-16 1.00000000e+00]]