4. 数学预备知识(下)

好,咱们接着聊。上一节我们把向量和矩阵的基本概念捋了一遍,这一节要动真格的了。矩阵运算、特征值、奇异值分解,这三个东西在模型辨识和策略训练里,简直就是家常便饭。我个人习惯,每次拿到一个新系统,第一件事就是看看它的矩阵结构长什么样,心里大概就有数了。

4.1 矩阵运算:不只是加减乘除

矩阵运算看着简单,但坑不少。我刚开始做控制的时候,就吃过亏。

4.1.1 矩阵乘法

矩阵乘法,说白了就是「行乘列」。但要注意,不满足交换律。AB 和 BA 通常不一样,甚至可能一个能乘,另一个根本乘不了。

核心规则:A(m×n) 乘以 B(n×p),结果 C 是 m×p 的。内维度必须相等。

举个例子:

import numpy as np

A = np.array([[1, 2], [3, 4]])  # 2x2
B = np.array([[5, 6], [7, 8]])  # 2x2

C = A @ B  # 或者 np.dot(A, B)
print(C)
# 输出: [[19 22]
#        [43 50]]

嗯,这里要注意:在 Python 里,@ 是矩阵乘法,* 是逐元素乘法。我见过不少新手在这上面翻车。

4.1.2 矩阵的逆与伪逆

矩阵的逆,只有方阵且满秩的时候才存在。但在实际工程中,我们遇到的矩阵往往不是方阵,或者不满秩。这时候就需要伪逆了。

我的经验:在系统辨识中,我们经常用最小二乘法。这时候伪逆就是救星。比如你有一堆测量数据,想拟合一个模型,直接求逆可能炸了,但伪逆稳稳的。

# 伪逆示例
A = np.array([[1, 2], [3, 4], [5, 6]])  # 3x2 矩阵
A_pinv = np.linalg.pinv(A)
print(A_pinv)

4.1.3 矩阵的迹与范数

迹就是对角线元素之和。范数嘛,可以理解为矩阵的「大小」。常用的有 Frobenius 范数,就是所有元素平方和再开方。

范数类型 公式 用途
Frobenius 范数 ||A||_F = sqrt(Σ a_ij²) 衡量误差矩阵
2-范数(谱范数) ||A||_2 = σ_max(A) 最大奇异值
1-范数 ||A||_1 = max_j Σ_i |a_ij| 列和最大

4.2 特征值与特征向量:系统的「灵魂」

特征值这个东西,你想想看,它描述了一个矩阵在变换时,哪些方向被拉伸了,哪些方向被压缩了。在控制理论里,特征值直接决定了系统的稳定性。

4.2.1 定义与几何意义

对于方阵 A,如果存在非零向量 v 和标量 λ,使得:

A v = λ v

那么 λ 就是特征值,v 就是对应的特征向量。几何上,特征向量方向上的向量,经过 A 变换后,只改变长度,不改变方向。

我曾经踩过的坑:在辨识一个机械臂的动力学模型时,算出来的特征值有正有负。我当时没在意,结果仿真直接炸了。后来才发现,正特征值对应的是不稳定模态。所以,看到特征值有正数,一定要警惕!

4.2.2 特征值分解

如果 A 可以对角化,那么:

A = V Λ V⁻¹

其中 V 的列是特征向量,Λ 是对角矩阵,对角线上是特征值。

import numpy as np

A = np.array([[4, 1], [2, 3]])
eigvals, eigvecs = np.linalg.eig(A)

print("特征值:", eigvals)
print("特征向量:\n", eigvecs)

4.2.3 在策略训练中的应用

在强化学习中,我们经常用特征值来分析值函数的收敛性。比如,贝尔曼算子的谱半径(最大特征值的值)如果小于 1,那迭代就收敛。否则,就发散。

一句话总结:特征值告诉你系统「稳不稳」,特征向量告诉你「往哪稳」。

4.3 奇异值分解(SVD):矩阵的「万能钥匙」

如果说特征值分解只适用于方阵,那 SVD 就是所有矩阵的福音。任何矩阵都能做 SVD,而且它比特征值分解更稳定、更强大。

4.3.1 SVD 的定义

对于任意矩阵 A (m×n),可以分解为:

A = U Σ Vᵀ

其中:

  • U 是 m×m 的正交矩阵(左奇异向量)
  • Σ 是 m×n 的对角矩阵(奇异值从大到小排列)
  • V 是 n×n 的正交矩阵(右奇异向量)

4.3.2 SVD 的几何解释

说白了,SVD 就是把一个线性变换拆成三步:旋转(Vᵀ)、拉伸(Σ)、再旋转(U)。你想想看,任何复杂的矩阵变换,本质上就是这三个动作的组合。

我的习惯:在模型辨识中,我拿到数据矩阵后,第一件事就是做 SVD。看看奇异值的分布,就能判断数据是「有效信息多」还是「噪声多」。如果奇异值衰减很快,说明有效维度很低,可以用低秩近似。

4.3.3 SVD 在策略训练中的实战

在策略梯度方法中,我们经常需要处理高维观测空间。SVD 可以用来做降维,提取主要特征。比如:

# 假设 X 是观测数据矩阵 (样本数 x 特征数)
U, s, Vt = np.linalg.svd(X, full_matrices=False)

# 保留前 k 个奇异值,实现降维
k = 10
X_reduced = U[:, :k] @ np.diag(s[:k])
print("降维后的数据形状:", X_reduced.shape)

4.3.4 奇异值与特征值的关系

这里有个有趣的联系:矩阵 A 的奇异值的平方,等于 AᵀA 的特征值。所以,SVD 某种意义上比特征值分解更「底层」。

性质 特征值分解 奇异值分解
适用矩阵 仅方阵 任意矩阵
数值稳定性 一般 优秀
物理意义 系统模态 能量分布
计算复杂度 O(n³) O(mn²)

4.4 本章知识体系

下面这张图,是我自己梳理的本章核心逻辑。你看一眼,就能明白这些知识点是怎么串起来的。

线性代数基础 矩阵运算 特征值分解 奇异值分解 乘法/逆/伪逆 迹与范数 特征向量 系统稳定性 U Σ Vᵀ 降维/去噪 模型辨识 & 策略训练 三大工具共同支撑起模型辨识与策略训练的数学基础

4.5 实战中的避坑指南

最后,分享几个我这些年积累的经验:

  • 数值稳定性:计算特征值时,尽量用 np.linalg.eig 而不是手算。手算容易炸。
  • 矩阵条件数:条件数太大的矩阵,求逆会很不稳定。SVD 可以帮你诊断这个问题。
  • 低秩近似:在策略训练中,如果状态空间很大,试试用 SVD 做低秩近似。我试过,训练速度能快 3-5 倍。
  • 不要迷信特征值:特征值只适用于方阵。遇到非方阵,老老实实用 SVD。

我曾经犯过的错:有一次做系统辨识,我直接用特征值分解分析一个非方阵的数据矩阵,结果算出来的东西完全不对。后来才意识到,非方阵要用 SVD。嗯,从那以后,我每次做矩阵分析前,都会先看一眼矩阵的形状。

好了,这一节的内容就到这。矩阵运算、特征值、SVD,这三板斧用好了,后面的模型辨识和策略训练,你会觉得顺手很多。