NumPy 线性代数
NumPy 提供了强大的线性代数功能,主要通过其子模块 numpy.linalg
实现。这些功能支持矩阵运算、向量运算、特征值分解、线性方程组求解等线性代数操作,广泛应用于科学计算、机器学习和工程领域。以下是对 NumPy 线性代数功能的详细中文讲解,涵盖核心功能、常见操作和示例。
1. 概述
numpy.linalg
模块提供了丰富的线性代数工具,用于处理矩阵和向量的运算。以下是主要功能的分类:
- 矩阵运算:矩阵乘法、转置、逆矩阵、行列式等。
- 线性方程组求解:求解
Ax = b
形式的方程。 - 特征值与特征向量:计算矩阵的特征值和特征向量。
- 矩阵分解:如 SVD(奇异值分解)、QR 分解等。
- 范数与距离:计算矩阵或向量的范数。
要使用线性代数功能,需先导入 NumPy 和 linalg
模块:
import numpy as np
import numpy.linalg as la
2. 基本矩阵运算
以下是常见的矩阵操作及其实现方法。
2.1 矩阵乘法
矩阵乘法可以通过 np.dot()
或 @
运算符实现(numpy.matrix
类的 *
也支持矩阵乘法,但建议使用 ndarray
)。
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 使用 @ 运算符
result = A @ B
print(result)
# 输出:
# [[19 22]
# [43 50]]
# 使用 np.dot
result_dot = np.dot(A, B)
print(result_dot)
# 输出同上
2.2 矩阵转置
使用 np.transpose()
或 .T
属性计算矩阵转置。
A = np.array([[1, 2], [3, 4]])
print(A.T)
# 输出:
# [[1 3]
# [2 4]]
2.3 矩阵的逆
使用 la.inv()
计算方阵的逆(矩阵必须是非奇异的,即行列式不为 0)。
A = np.array([[1, 2], [3, 4]])
A_inv = la.inv(A)
print(A_inv)
# 输出:
# [[-2. 1. ]
# [ 1.5 -0.5]]
# 验证:A @ A_inv 应为单位矩阵
print(A @ A_inv)
# 输出:
# [[1. 0.]
# [0. 1.]]
2.4 矩阵的行列式
使用 la.det()
计算矩阵的行列式。
A = np.array([[1, 2], [3, 4]])
det = la.det(A)
print(det) # 输出: -2.0
2.5 矩阵的迹
矩阵的迹是主对角线元素之和,可用 np.trace()
计算。
A = np.array([[1, 2], [3, 4]])
trace = np.trace(A)
print(trace) # 输出: 5 (1 + 4)
3. 线性方程组求解
求解线性方程组 Ax = b
,其中 A
是系数矩阵,x
是未知向量,b
是常数向量。使用 la.solve()
求解。
示例:
求解以下方程组:
2x + y = 5
x + 3y = 10
代码:
A = np.array([[2, 1], [1, 3]])
b = np.array([5, 10])
x = la.solve(A, b)
print(x) # 输出: [1. 3.] (即 x = 1, y = 3)
注意:
la.solve()
适用于方阵(A
必须是 n×n 矩阵)。- 如果
A
不可逆(奇异矩阵),会抛出LinAlgError
。
4. 特征值与特征向量
使用 la.eig()
计算方阵的特征值和特征向量。
示例:
A = np.array([[1, 2], [2, 1]])
eigenvalues, eigenvectors = la.eig(A)
print("特征值:", eigenvalues)
print("特征向量:\n", eigenvectors)
# 输出:
# 特征值: [ 3. -1.]
# 特征向量:
# [[ 0.70710678 -0.70710678]
# [ 0.70710678 0.70710678]]
解释:
eigenvalues
是一个一维数组,包含矩阵的特征值。eigenvectors
是一个矩阵,每列是对应特征值的特征向量。
5. 矩阵分解
numpy.linalg
支持多种矩阵分解方法,常用的包括:
5.1 奇异值分解 (SVD)
SVD 将矩阵 A
分解为 U @ np.diag(s) @ Vh
,其中 U
和 Vh
是正交矩阵,s
是奇异值向量。
A = np.array([[1, 2], [3, 4]])
U, s, Vh = la.svd(A)
print("U:\n", U)
print("奇异值:", s)
print("Vh:\n", Vh)
# 输出示例:
# U:
# [[-0.40455358 -0.9145143 ]
# [-0.9145143 0.40455358]]
# 奇异值: [5.4649857 0.36596619]
# Vh:
# [[-0.57604844 -0.81741556]
# [-0.81741556 0.57604844]]
5.2 QR 分解
QR 分解将矩阵分解为正交矩阵 Q
和上三角矩阵 R
。
A = np.array([[1, 2], [3, 4]])
Q, R = la.qr(A)
print("Q:\n", Q)
print("R:\n", R)
# 输出示例:
# Q:
# [[-0.31622777 -0.9486833 ]
# [-0.9486833 0.31622777]]
# R:
# [[-3.16227766 -4.42718872]
# [ 0. -0.63245553]]
6. 范数与距离
6.1 矩阵或向量的范数
使用 la.norm()
计算范数(默认是 L2 范数)。
v = np.array([3, 4])
norm = la.norm(v)
print(norm) # 输出: 5.0 (sqrt(3^2 + 4^2))
# 矩阵范数
A = np.array([[1, 2], [3, 4]])
norm_A = la.norm(A) # 默认 Frobenius 范数
print(norm_A) # 输出: 5.477225575051661
6.2 其他范数
支持的范数类型包括:
ord='fro'
:Frobenius 范数(矩阵默认)。ord=2
:L2 范数(向量默认)。ord=1
:L1 范数。ord=np.inf
:无穷范数。
7. 其他实用功能
7.1 矩阵的条件数
条件数衡量矩阵的数值稳定性,使用 la.cond()
计算。
A = np.array([[1, 2], [3, 4]])
cond = la.cond(A)
print(cond) # 输出: 14.933034373659268
7.2 矩阵的秩
使用 la.matrix_rank()
计算矩阵的秩。
A = np.array([[1, 2], [2, 4]])
rank = la.matrix_rank(A)
print(rank) # 输出: 1 (因为矩阵是奇异的)
7.3 伪逆
对于非方阵或奇异矩阵,可用 la.pinv()
计算伪逆。
A = np.array([[1, 2], [3, 4]])
A_pinv = la.pinv(A)
print(A_pinv)
# 输出:
# [[-2. 1. ]
# [ 1.5 -0.5]]
8. 注意事项
- 矩阵 vs 数组:
- NumPy 推荐使用
ndarray
而不是numpy.matrix
,因为ndarray
更通用,matrix
类的特殊行为(如*
表示矩阵乘法)可能导致混淆。 - 使用
@
运算符和np.dot()
可以完全替代matrix
类的矩阵乘法。
- 数值稳定性:
- 对于接近奇异的矩阵(如行列式接近 0),
la.inv()
或la.solve()
可能因数值误差导致不准确。 - 使用 SVD 或伪逆可以处理这类情况。
- 性能:
- 大矩阵运算可能需要优化,考虑使用稀疏矩阵(
scipy.sparse
)或并行计算。
- 输入要求:
- 许多
linalg
函数要求输入是二维数组(矩阵)或一维数组(向量),需确保形状正确。
9. 示例:综合应用
假设要分析一个线性系统,计算其特征值、解方程组并验证结果:
# 定义矩阵和向量
A = np.array([[4, -1], [2, 1]])
b = np.array([1, 2])
# 求解线性方程组 Ax = b
x = la.solve(A, b)
print("解 x:", x) # 输出: [0.5 1. ]
# 计算特征值和特征向量
eigvals, eigvecs = la.eig(A)
print("特征值:", eigvals)
print("特征向量:\n", eigvecs)
# 验证解
print("验证 Ax:", A @ x) # 输出: [1. 2.] (与 b 一致)
10. 总结
numpy.linalg
提供了全面的线性代数工具,涵盖矩阵运算、方程求解、特征值分析和矩阵分解。- 核心函数包括
la.inv()
、la.solve()
、la.eig()
、la.svd()
等。 - 推荐使用
ndarray
而非numpy.matrix
,因为前者更灵活且是 NumPy 的核心数据结构。 - 注意数值稳定性、输入格式和性能优化,确保代码高效且正确。
如果有具体线性代数问题或需要更详细的示例,请告诉我!