scipy.linalg是SciPy中负责线性代数计算的模块。NumPy也有numpy.linalg模块,不过建议使用scipy.linalg,原因有二:
import numpy.linalg
import scipy.linalg
len(dir(numpy.linalg))
34
len(dir(scipy.linalg))
156
import numpy as np
from scipy import linalg
在NumPy中,矩阵有两种表示方法:矩阵类型和二维数组类型。
矩阵类型可以用np.mat()
或者np.matrix()
创建:
A = np.mat("[1, 2; 3, 4]")
A
matrix([[1, 2], [3, 4]])
A = np.matrix("[1, 2; 3, 4]")
A
matrix([[1, 2], [3, 4]])
转置矩阵为:
A.T
matrix([[1, 3], [2, 4]])
矩阵的逆矩阵:
A.I
matrix([[-2. , 1. ], [ 1.5, -0.5]])
矩阵乘法:
A.I * A
matrix([[1.00000000e+00, 0.00000000e+00], [1.11022302e-16, 1.00000000e+00]])
A * A.I
matrix([[1.0000000e+00, 0.0000000e+00], [8.8817842e-16, 1.0000000e+00]])
数组类型也可以完成类似的操作:
A = np.array([[1, 2], [3, 4]])
A
array([[1, 2], [3, 4]])
转置:
A.T
array([[1, 3], [2, 4]])
其逆矩阵可以用linalg.inv()
函数计算:
A.dot(linalg.inv(A))
array([[1.0000000e+00, 0.0000000e+00], [8.8817842e-16, 1.0000000e+00]])
A @ linalg.inv(A)
array([[1.0000000e+00, 0.0000000e+00], [8.8817842e-16, 1.0000000e+00]])
linalg.inv(A) @ A
array([[1.00000000e+00, 0.00000000e+00], [1.11022302e-16, 1.00000000e+00]])
scipy.linalg
也可以作用在矩阵类型上,返回的还是一个数组:
A = np.matrix([[1, 2], [3, 4]])
linalg.inv(A)
array([[-2. , 1. ], [ 1.5, -0.5]])
矩阵类型的使用比较少,通常都用数组类型替代矩阵类型进行计算。
考虑下列方程组:
x + 3y + 5z = 10
2x + 5y - z = 8
2x + 3y + 8z = 3
矩阵形式为: [13525−1238][xyz]=[1083]
其解为: [xyz]=[13525−1238]−1[1083]
故:
A = np.array([[1, 3, 5],
[2, 5, -1],
[2, 3, 8]])
b = np.array([10, 8, 3])
解:
linalg.inv(A) @ b
array([-8.83870968, 5.25806452, 0.61290323])
也可以直接使用linalg.solve()
函数,直接求解这个方程:
linalg.solve(A, b)
array([-8.83870968, 5.25806452, 0.61290323])
linalg.det()
函数可以计算矩阵的行列式:
linalg.det(A)
-31.000000000000007
行列式非零表示矩阵是可逆的。逆矩阵的行列式与矩阵的行列式满足相乘等于1的关系:
linalg.det(linalg.inv(A))
-0.03225806451612903
linalg.det(linalg.inv(A)) * linalg.det(A)
1.0000000000000002
A = np.array([[1, 2], [3, 4]])
默认情况下,linalg.norm()
函数计算的是矩阵的Frobenius范数,该范数计算的是矩阵所有元素平方和的平方根:
linalg.norm(A)
5.477225575051661
linalg.norm(A, "fro")
5.477225575051661
可以通过linalg.norm()
函数中的第二个参数,来修改矩阵范数的计算方法。例如,矩阵的1范数,计算的是矩阵中每列元素的和的最大值:
linalg.norm(A, 1)
6.0
矩阵的-1范数,计算的是矩阵中每列元素的和的最小值:
linalg.norm(A, -1)
4.0
矩阵的2范数,计算的是矩阵的最大奇异值:
linalg.norm(A, 2)
5.464985704219043
矩阵的-2范数,计算的是矩阵的最小奇异值:
linalg.norm(A, -2)
0.36596619062625746
矩阵的正无穷范数,计算的是矩阵中每行元素的和的最大值:
linalg.norm(A, np.inf)
7.0
矩阵的负无穷范数,计算的是矩阵中每行元素的和的最小值:
linalg.norm(A, -np.inf)
3.0
linalg.norm()
函数也可以用来计算向量的范数(也称模):
b = np.array([10, 8, 3])
对于向量来说,linalg.norm()函数默认是向量的2范数,即计算向量元素的平方和的平方根:
linalg.norm(b)
13.152946437965905
linalg.norm(b, 2)
13.152946437965905
对于方阵A,特征值λ和特征向量v满足:Av=λv
。函数linalg.eig()
可以用来求解特征值和特征向量:
A = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
l, v = linalg.eig(A)
np.allclose(A.dot(v), l * v)
True
对于形状为m×n的矩阵A,可以用linalg.pinv()
求解其广义逆。A的广义逆B满足:A=ABA
,B=ABA
:
A = np.array([[1, 2, 3],
[4, 5, 6]])
B = linalg.pinv(A)
np.allclose(A, A @ B @ A)
True
np.allclose(B, B @ A @ B)
True
对于形状为m×n的矩阵A,其奇异值分解满足A=U\SigmaVH,矩阵Σ形状为M×N,主对角线上的元素被称为奇异值。U、V分别为M阶、N阶正交单位矩阵。
函数linalg.svd()
可以对矩阵进行奇异值分解:
U, s, Vh = linalg.svd(A)
U
array([[-0.3863177 , -0.92236578], [-0.92236578, 0.3863177 ]])
s
array([9.508032 , 0.77286964])
Vh
array([[-0.42866713, -0.56630692, -0.7039467 ], [ 0.80596391, 0.11238241, -0.58119908], [ 0.40824829, -0.81649658, 0.40824829]])
从奇异值恢复矩阵Σ:
S = linalg.diagsvd(s, 2, 3)
np.allclose(A, U @ S @ Vh)
True
正交矩阵:
U @ U.T
array([[ 1.00000000e+00, -8.49433239e-18], [-8.49433239e-18, 1.00000000e+00]])
Vh @ Vh.T
array([[ 1.00000000e+00, 4.13108370e-17, 2.21870637e-17], [ 4.13108370e-17, 1.00000000e+00, -1.77008767e-16], [ 2.21870637e-17, -1.77008767e-16, 1.00000000e+00]])