第三部分:矩阵运算与线性代数(计算篇)
矩阵计算与线性代数是科学计算的核心。在摆脱传统商业软件、转向 Python 科学计算生态时,深刻理解 NumPy 的底层代数运算规则是构建高效仿真系统(如状态空间求解、系统参数辨识)的关键所在。本篇将全面解析从标量广播到高级矩阵分解的核心方法。
1. 广播机制(Broadcasting)
广播是 NumPy 最强大的特性之一。当两个形状不完全相同的数组进行算术运算时,NumPy 会自动触发广播机制,通过在虚拟层面上"复制"较小数组的维度,使其形状与较大数组对齐,从而避免了显式的 Python 循环。
核心规则:从右往左比对数组的形状维度。如果两个维度相等,或者其中一个维度为 1,则它们是兼容的。
-
广播运算示例:
在多智能体系统仿真中,常需要给一批智能体的状态矩阵加上同一个全局偏移向量。
pythonimport numpy as np # 3 个智能体的二维坐标矩阵,形状 (3, 2) agent_states = np.array([[10.0, 20.0], [15.0, 25.0], [5.0, 10.0]]) # 全局坐标偏移向量,形状 (2,) offset = np.array([-5.0, 5.0]) # 触发广播:(2,) 会被看作 (1, 2),然后在第 0 维复制 3 次匹配 (3, 2) updated_states = agent_states + offset print(updated_states) # [[ 5. 25.] # [10. 30.] # [ 0. 15.]]
2. 逐元素运算
所有的加减乘除(+, -, *, /)以及数学函数默认都是逐元素(Element-wise)执行的。这与线性代数中的矩阵乘法完全不同。
-
四则运算与非线性激活:
pythonA = np.array([[1, 2], [3, 4]]) B = np.array([[2, 2], [2, 2]]) # 逐元素乘法(哈达玛积),对应位置元素相乘 element_mul = A * B print(element_mul) # [[2 4] # [6 8]] # 常见非线性数学函数 exp_A = np.exp(A) # e^x log_A = np.log(A) # ln(x) sqrt_A = np.sqrt(A) # 根号 x
3. 点积与矩阵乘法
这是控制理论与信号处理中最频繁的操作,用于计算状态转移 xk+1=Axk+Bukx_{k+1} = Ax_k + Bu_kxk+1=Axk+Buk 或构建增益矩阵。
-
np.dot,@,np.matmul:这三者在处理二维矩阵时功能等价,都执行标准的矩阵乘法。工程实践中,最推荐使用 Python 3.5 引入的
@运算符,代码最具可读性。对于高维张量(Batch 运算),@和np.matmul会将最后两个维度视为矩阵进行批量乘法。pythonA = np.array([[1, 2], [3, 4]]) # 状态矩阵 (2, 2) x = np.array([[1], [2]]) # 状态向量 (2, 1) # 标准矩阵乘法 x_next = A @ x # 等价于 np.matmul(A, x) 或 np.dot(A, x) print(x_next) # [[ 5] # [11]] -
np.inner与np.outer:内积用于计算向量投影或误差标量,外积(张量积)常用于自适应算法中基于单个误差向量对权重矩阵进行秩一更新。
pythonu = np.array([1, 2, 3]) v = np.array([0, 1, 0]) # 内积:计算对应元素乘积之和 inner_prod = np.inner(u, v) print(inner_prod) # 2 # 外积:u 作为列向量乘 v 作为行向量,生成 (3, 3) 矩阵 outer_prod = np.outer(u, v) print(outer_prod) # [[0 1 0] # [0 2 0] # [0 3 0]]
4. 高级线性代数(np.linalg 模块)
np.linalg 封装了底层的 BLAS/LAPACK 库,用于处理复杂的矩阵代数运算。
-
逆矩阵与伪逆(
inv,pinv):当方阵满秩时使用
inv求逆。在无模型自适应控制或数据驱动辨识中,输入输出数据矩阵往往不是方阵,此时需要通过广义逆(伪逆)来求解最小二乘参数估计。pythonfrom numpy.linalg import inv, pinv # 满秩方阵求逆 M = np.array([[1, 2], [3, 4]]) M_inv = inv(M) # 非方阵求伪逆(例如 3 个样本,2 个特征的数据矩阵) Phi = np.array([[1, 0], [1, 1], [0, 1]]) Phi_pinv = pinv(Phi) print(Phi_pinv) # [[ 0.66666667 0.33333333 -0.33333333] # [-0.33333333 0.33333333 0.66666667]] -
特征值与特征向量(
eig,eigh):用于分析系统状态矩阵的极点分布,判断动力学系统的稳定性。如果已知矩阵是对称阵(如李雅普诺夫方程中的 PPP 矩阵或协方差矩阵),使用
eigh计算速度更快且在数值上更稳定。pythonfrom numpy.linalg import eig, eigh A = np.array([[0, 1], [-2, -3]]) # 计算特征值与特征向量 eigenvalues, eigenvectors = eig(A) print("系统极点:", eigenvalues) # 系统极点: [-1. -2.] (实部均小于0,连续系统稳定) # 对称阵的特征值计算 P = np.array([[2, 1], [1, 2]]) evals_sym, evecs_sym = eigh(P) -
矩阵分解与度量(
svd,cholesky,norm,det):奇异值分解(SVD)常用于降维或能控/能观性分析;Cholesky 分解用于正定矩阵;范数用于衡量误差大小或协同控制中的相对距离;行列式用于判断矩阵是否可逆。
pythonfrom numpy.linalg import svd, cholesky, norm, det # 1. 奇异值分解 SVD # 将矩阵分解为 U, Sigma, V^T Data = np.array([[1, 2, 0], [0, 1, 1]]) U, S, Vh = svd(Data) print("奇异值:", S) # 奇异值: [2.31295259 0.81232822] # 2. Cholesky 分解(要求方阵对称正定) # 分解为下三角矩阵 L,满足 P = L @ L.T L = cholesky(P) # 3. 向量/矩阵范数(默认求解 2-范数/欧几里得距离) err = np.array([3, -4]) error_norm = norm(err) print("误差 L2 范数:", error_norm) # 误差 L2 范数: 5.0 # 4. 行列式计算 matrix_det = det(M) print("行列式值:", matrix_det) # 行列式值: -2.0000000000000004