18.06 第 24b 讲:第二次测验复习
- 118.06 第 1 讲:方程组的行图与列图
- 218.06 第 2 讲:用矩阵做消元
- 318.06 第 3 讲:矩阵乘法的四种看法与逆矩阵
- 418.06 第 4 讲:分解成 A = LU
- 518.06 第 5 讲:转置、置换与向量空间
- 618.06 第 6 讲:列空间与零空间
- 718.06 第 7 讲:解 Ax = 0,主变量与特解
- 818.06 第 8 讲:解 Ax = b,行最简形 R
- 918.06 第 9 讲:线性无关、基与维数
- 1018.06 第 10 讲:四个基本子空间
- 1118.06 第 11 讲:矩阵空间、秩 1 矩阵与小世界图
- 1218.06 第 12 讲:图、网络与关联矩阵
- 1318.06 第 13 讲:第一次测验复习
- 1418.06 第 14 讲:正交向量与正交子空间
- 1518.06 第 15 讲:投影到子空间
- 1618.06 第 16 讲:投影矩阵与最小二乘
- 1718.06 第 17 讲:正交矩阵与 Gram-Schmidt
- 1818.06 第 18 讲:行列式的性质
- 1918.06 第 19 讲:行列式公式与代数余子式
- 2018.06 第 20 讲:Cramer 法则、逆矩阵与体积
- 2118.06 第 21 讲:特征值与特征向量
- 2218.06 第 22 讲:对角化与矩阵的幂
- 2318.06 第 23 讲:微分方程与 exp(At)
- 2418.06 第 24 讲:Markov 矩阵与 Fourier 级数
- 2518.06 第 24b 讲:第二次测验复习本文
- 2618.06 第 25 讲:对称矩阵与正定性
- 2718.06 第 26 讲:复矩阵与快速 Fourier 变换
- 2818.06 第 27 讲:正定矩阵与极小值
- 2918.06 第 28 讲:相似矩阵与 Jordan 标准形
- 3018.06 第 29 讲:奇异值分解
- 3118.06 第 30 讲:线性变换及其矩阵
- 3218.06 第 31 讲:基变换与图像压缩
- 3318.06 第 32 讲:第三次测验复习
- 3418.06 第 33 讲:左逆、右逆与伪逆
- 3518.06 第 34 讲:期末复习
这一讲没有新东西,Strang 拿两份旧试卷(1984 年的期中,1992 年的期末)把第四到六章串了一遍:投影、最小二乘、Gram-Schmidt、行列式、特征值。我把他黑板上的每道题都交给 NumPy 重算,最有意思的两个结果是:一个投影矩阵作用一次之后,迭代 就再也不动了,停在 ;一个看起来像 Fibonacci 的递推,递推矩阵的六次幂恰好是单位矩阵,周期是 6。
视频:Lecture 24b: Quiz 2 review(OCW 页面与字幕) 教材:《Introduction to Linear Algebra》第 6 版 第 4 到 6 章 前置:第 24 讲:Markov 矩阵与 Fourier 级数 一句话:投影矩阵、特征值、行列式和差分方程不是四个话题,而是同一个矩阵的四种问法,一道题常常把它们连着问。
- 开头几分钟他把第二部分的内容列了一遍(、投影、最小二乘、Gram-Schmidt,行列式的十条性质,特征值与矩阵的幂)。这一段值得听,它是一份考点清单,也是本篇小节顺序的依据。
- 投影、拟合直线和 Gram-Schmidt 三题他讲得很快,本篇都用代码算过,可以倍速。但“最小二乘有两幅图”的那一段要认真听:一幅在 - 平面里,一幅在 所在的空间里。
- 行列式递推那一题(从余子式到一阶系统,再到复特征值)是整堂课的重头戏,值得完整看一遍。
- 结尾他猜“奇数阶的奇异,偶数阶的可逆”,本篇最后一节用代码验证了。
先看清考什么
开头他把范围列得很清楚。第四章是正交: 的列是标准正交向量,写成矩阵语言就是 ;然后是投影到直线和子空间,用投影解无解的 (最小二乘),最后是 Gram-Schmidt,把一组无关向量变成标准正交基。第五章是行列式:性质 1 到 3 定义了行列式,性质 4 到 10 是推论,再加上有 项的大公式、余子式公式,以及由此得到的逆矩阵公式。第六章只考到 6.1 和 6.2,也就是特征值、 的机械步骤、对角化与矩阵的幂。微分方程(教材第 6 版 §6.5,对应视频里说的 6.3)留给第三次测验。
他说他复习的办法一般是拿一份旧试卷,挑出有代表性的题,边写边讲。这份试卷是 1984 年 11 月的,“那时候连 Web 都没有”。我就按他黑板上的顺序走。(这篇没有新定理,我的贡献是把他心算的几十个数交给 NumPy 再核对一遍,相当于给黑板配了一台计算器。)
投影矩阵、特征值和差分方程
第一题给了 ,求投影到过 的直线上的矩阵 。直线情形下一般公式 里的 只有一列, 是一个数 ,所以
接着他一路追问:秩是多少?列空间是什么?特征值是什么?答案分别是 1、这条直线、。秩 1 意味着零空间是二维的,所以特征值 0 重复两次;第三个特征值从迹得到,;特征值 1 对应的特征向量是 本身,因为 (不动的向量)。
最后一问是解 ,。他直接算 :,除以 得 3,所以 。已经在直线上的点再投影一次不会动,所以 全是 。
import numpy as np
def main() -> None: np.set_printoptions(precision=4, suppress=True) a = np.array([2.0, 1.0, 2.0]) P = np.outer(a, a) / (a @ a) print("9 P =") print(9 * P) print("P @ P == P:", np.allclose(P @ P, P)) print("P.T == P:", np.allclose(P.T, P)) print("秩:", np.linalg.matrix_rank(P), ",迹:", np.trace(P))
# 特征值:两个 0 和一个 1,特征值 1 的特征向量是 a 本身 print("特征值:", np.sort(np.linalg.eigvalsh(P)).round(8) + 0.0) print("P @ a =", P @ a)
# 差分方程 u(k+1) = P u(k),u0 = (9, 9, 0) u0 = np.array([9.0, 9.0, 0.0]) u = u0 for k in range(1, 4): u = P @ u print(f"u{k} =", u)
# 对照:直接算 P^10 @ u0 print("P^10 @ u0 =", np.linalg.matrix_power(P, 10) @ u0)
if __name__ == "__main__": main()9 P =[[4. 2. 4.] [2. 1. 2.] [4. 2. 4.]]P @ P == P: TrueP.T == P: True秩: 1 ,迹: 1.0特征值: [0. 0. 1.]P @ a = [2. 1. 2.]u1 = [6. 3. 6.]u2 = [6. 3. 6.]u3 = [6. 3. 6.]P^10 @ u0 = [6. 3. 6.]输出里最要紧的是 到 完全一样,和直接算 的结果也一样。对投影矩阵来说 ,所以不用做特征分解。他特意提醒:考试里这道题很可能换成一个不是投影的矩阵,那时就老老实实走三步,找特征值、找特征向量、解出 里的系数 ,然后 。投影矩阵的两个 0 特征值把另外两项直接扔掉,只剩 。
过原点的直线与 Gram-Schmidt
第二题拟合经过原点的直线 ,三个点是 、、。只有一个未知数 ,所以 只有一列:
正规方程 是 ,所以 。他接着问了一个我觉得最像考试陷阱的问题:刚才到底把什么向量投影到了什么上面?答案是,在 - 平面的那张图里什么都没有被投影;投影发生在 所在的三维空间里,把 投到 的列空间(这里是一条线)上。
同一道大题的最后一问是 Gram-Schmidt:,,找这个平面里两个正交的向量。保留 ,把 里沿 的部分减掉:。题目只要正交,不要单位化,所以不用开方。
import numpy as np
def main() -> None: np.set_printoptions(precision=4, suppress=True)
# 过原点的直线 y = D t,三个点 (1, 4)、(2, 5)、(3, 8) A = np.array([[1.0], [2.0], [3.0]]) b = np.array([4.0, 5.0, 8.0]) AtA = (A.T @ A)[0, 0] Atb = (A.T @ b)[0] D = Atb / AtA print("AᵀA =", AtA, ",Aᵀb =", Atb) print(f"D = 38/14 = {D:.4f},{np.isclose(D, 38 / 14)}")
x, *_ = np.linalg.lstsq(A, b, rcond=None) print(f"lstsq 的 D = {x[0]:.4f},一致:{np.allclose(x[0], D)}")
# 投影图:b 投影到 A 的列空间,误差与列空间正交 p = A[:, 0] * D e = b - p print("p =", p) print("e =", e) print("Aᵀe 为零:", np.allclose(A.T @ e, 0.0))
# Gram-Schmidt:a1 = (1, 2, 3),a2 = (1, 1, 1) a1 = np.array([1.0, 2.0, 3.0]) a2 = np.array([1.0, 1.0, 1.0]) B = a2 - (a1 @ a2) / (a1 @ a1) * a1 print("a1ᵀa2 =", a1 @ a2, ",a1ᵀa1 =", a1 @ a1) print("14 B =", 14 * B) print("a1 与 B 正交:", np.isclose(a1 @ B, 0.0))
# 对照 np.linalg.qr:单位化之后,两组向量最多差一个符号 Q, _ = np.linalg.qr(np.column_stack([a1, a2])) mine = np.column_stack([a1 / np.linalg.norm(a1), B / np.linalg.norm(B)]) print("与 qr 一致:", np.allclose(np.abs(Q), np.abs(mine)))
if __name__ == "__main__": main()AᵀA = 14.0 ,Aᵀb = 38.0D = 38/14 = 2.7143,Truelstsq 的 D = 2.7143,一致:Truep = [2.7143 5.4286 8.1429]e = [ 1.2857 -0.4286 -0.1429]Aᵀe 为零: Truea1ᵀa2 = 6.0 ,a1ᵀa1 = 14.014 B = [ 8. 2. -4.]a1 与 B 正交: True与 qr 一致: True,也就是 。 与 正交,单位化之后和 np.linalg.qr 给出的两列在符号之外一致(QR 的符号取决于实现,所以我比较的是绝对值)。顺带验证了拟合的误差 与列空间垂直。
特征值的几条“白送”的性质
第三题是一个 矩阵 ,特征值是 ,问三件事:
- 可逆的条件?没有零特征值(零特征值就是零空间里有非零向量)。
- ? 的特征值是 ,行列式是它们的积,即 。
- ? 的特征值是 ,迹是它们的和,即 。
他没有给矩阵,所以我自己造一个:取特征值 ,用 ( 是随机矩阵)造出来,再逐条核对。
import numpy as np
def main() -> None: rng = np.random.default_rng(1806)
# 构造一个特征值已知的 4 x 4 矩阵 A = S diag(lam) S^-1 lam = np.array([2.0, -1.0, 0.5, 3.0]) S = rng.standard_normal((4, 4)) A = S @ np.diag(lam) @ np.linalg.inv(S) eigs = np.sort(np.linalg.eigvals(A).real) print("特征值:", np.round(eigs, 4))
# 可逆当且仅当没有零特征值;det A 是特征值之积 print(f"det A = {np.linalg.det(A):.4f},积 = {np.prod(lam):.4f}") # A 的逆的行列式是 1 / (λ1 λ2 λ3 λ4) det_inv = np.linalg.det(np.linalg.inv(A)) print(f"det A⁻¹ = {det_inv:.4f},1/积 = {1 / np.prod(lam):.4f}") # A + I 的迹等于特征值之和再加 4 tr = np.trace(A + np.eye(4)) print(f"tr(A + I) = {tr:.4f},和 + 4 = {lam.sum() + 4:.4f}")
# 反过来:有一个特征值是 0 的矩阵不可逆 lam0 = np.array([2.0, -1.0, 0.0, 3.0]) B = S @ np.diag(lam0) @ np.linalg.inv(S) print("含 0 特征值的矩阵:秩 =", np.linalg.matrix_rank(B)) print(f"det = {np.linalg.det(B):.1e}")
if __name__ == "__main__": main()特征值: [-1. 0.5 2. 3. ]det A = -3.0000,积 = -3.0000det A⁻¹ = -0.3333,1/积 = -0.3333tr(A + I) = 8.5000,和 + 4 = 8.5000含 0 特征值的矩阵:秩 = 3det = -1.9e-15,正是 ; 的行列式是 ;。最后两行是反例:把一个特征值换成 0,行列式从 掉到 ,数值上就是 0(它的秩是 3,不是 4,因为这个矩阵可对角化,秩等于非零特征值的个数)。
行列式递推:从余子式到周期 6
这是我觉得整堂课最漂亮的一题。 是对角线、上下副对角线全是 1 的三对角矩阵,。第一问:用余子式证明 ,求 、。
他沿第一行展开。第一项是 。第二项是位置 上的 1,它的余子式要带一个负号;这个子矩阵的第一列只有一个非零元,再按第一列展开,得到 。所以符号叠起来是 :
他提醒这不是 Fibonacci,因为有一个负号。第二问是把二阶递推写成一阶系统,这是第 22 讲里对付 Fibonacci 的老办法:
的特征方程是 ,解是 。模长:实部平方 加虚部平方 ,等于 1,所以它们在单位圆上,。稳定吗?既不衰减也不爆炸,绕着圈转。题目还告诉你 ,所以 的特征值都是 1,对角化之后就是单位矩阵:转六步回到出发点。
import numpy as np
def tridiagonal_det(n: int) -> float: """对角线、上下副对角线全是 1 的 n 阶矩阵的行列式。""" A = np.eye(n) + np.eye(n, k=1) + np.eye(n, k=-1) return np.linalg.det(A)
def main() -> None: np.set_printoptions(precision=4, suppress=True)
# 递推 D(n) = D(n-1) - D(n-2),D1 = 1,D2 = 0 D = [1.0, 0.0] for _ in range(10): D.append(D[-1] - D[-2]) print("递推:", np.array(D)) direct = [tridiagonal_det(n) for n in range(1, 13)] print("直接算:", np.array(direct)) print("一致:", np.allclose(D, direct))
# 写成一阶系统 (D(n), D(n-1)) = M (D(n-1), D(n-2)) M = np.array([[1.0, -1.0], [1.0, 0.0]]) lam = np.linalg.eigvals(M) print("特征值:", lam) print("模长:", np.abs(lam)) print("辐角(度):", np.degrees(np.angle(lam))) print("λ^6 全为 1:", np.allclose(lam**6, 1.0)) M6 = np.linalg.matrix_power(M, 6) print("M^6 =") print(M6) print("M^6 是单位矩阵:", np.allclose(M6, np.eye(2)))
if __name__ == "__main__": main()递推: [ 1. 0. -1. -1. 0. 1. 1. 0. -1. -1. 0. 1.]直接算: [ 1. 0. -1. -1. 0. 1. 1. 0. -1. -1. 0. 1.]一致: True特征值: [0.5+0.866j 0.5-0.866j]模长: [1. 1.]辐角(度): [ 60. -60.]λ^6 全为 1: TrueM^6 =[[1. 0.] [0. 1.]]M^6 是单位矩阵: True递推给出的 是 重复两遍,和 np.linalg.det 直接算十二个三对角矩阵的结果完全一致。特征值的模长是 1,辐角是 度,,全都对得上。(他顺口说出“六次幂是单位矩阵”之后又自嘲,这本来是一道很好的测验题,不该脱口而出。)
1992 年期末:一族对称矩阵
后半堂课他换了一份 1992 年的期末卷,很多题围绕同一族矩阵:对角线全是 0,副对角线依次是 的对称矩阵。 是
他问的几件事: 奇异还是可逆?第三列是第一列的两倍,所以奇异,列空间是一个平面。求投影到这个平面的矩阵:取前两列做基,套 。再求特征值:,所以 。他说他不敢不查迹就写下这三个数:迹是 0,三个特征值加起来也是 0。(他也承认,行列式是 0,帮不上忙:如果那个 5 写成了 4,迹和行列式都抓不出来。)
最后是 的列空间上的投影矩阵,题目旁边写着“不难”。如果 可逆,列空间就是 ,投影矩阵就是 的单位矩阵,确实不难。可逆吗?沿第一行再沿第一列做两次余子式展开,。他于是猜:奇数阶的奇异,偶数阶的可逆。
import numpy as np
def family(n: int) -> np.ndarray: """对称矩阵,零对角线,副对角线是 1, 2, ..., n-1。""" v = np.arange(1.0, n) return np.diag(v, k=1) + np.diag(v, k=-1)
def main() -> None: np.set_printoptions(precision=4, suppress=True)
A3 = family(3) print("A3 =") print(A3) print("秩:", np.linalg.matrix_rank(A3), ",det =", np.linalg.det(A3))
# A3 奇异,列空间是平面:取前两列作基,P = B (BᵀB)⁻¹ Bᵀ B = A3[:, :2] P = B @ np.linalg.inv(B.T @ B) @ B.T print("P =") print(P) print("P @ A3 == A3:", np.allclose(P @ A3, A3)) print("与 A3 @ pinv(A3) 一致:", np.allclose(P, A3 @ np.linalg.pinv(A3)))
# 特征值:0 和 ±√5,迹为 0 print("A3 的特征值:", np.linalg.eigvalsh(A3)) print("±√5 =", np.sqrt(5.0), ",迹 =", np.trace(A3))
# A4 的行列式是 9,列空间是 R^4,投影矩阵是单位矩阵。逐阶看行列式 for n in range(1, 9): print(f"det A{n} =", round(np.linalg.det(family(n)), 6))
if __name__ == "__main__": main()A3 =[[0. 1. 0.] [1. 0. 2.] [0. 2. 0.]]秩: 2 ,det = 0.0P =[[0.2 0. 0.4] [0. 1. 0. ] [0.4 0. 0.8]]P @ A3 == A3: True与 A3 @ pinv(A3) 一致: TrueA3 的特征值: [-2.2361 0. 2.2361]±√5 = 2.23606797749979 ,迹 = 0.0det A1 = 0.0det A2 = -1.0det A3 = 0.0det A4 = 9.0det A5 = 0.0det A6 = -225.0det A7 = 0.0det A8 = 11025.0 的列确实落在平面里(),也和 A3 @ pinv(A3) 一致; 的特征值 就是 和 ;。我多算到 :奇数阶行列式全是 0,偶数阶是 ,绝对值分别是 ,也就是 的平方。他说他押这些行列式有漂亮的公式,至少到 8 阶,他押对了。
奇数阶为什么奇异,倒是可以一句话说清:令 的偶数位分量为 0,奇数阶矩阵里偶数行的方程只含奇数位分量,个数比未知数少一个,所以必有非零解 。偶数阶的公式我只验证了数值,没有证明。
下一讲回到新内容:对称矩阵与正定性。刚才反复出现的 、 都是对称的,这不是巧合:对称矩阵的特征值一定是实数,特征向量可以取成互相正交的,下一讲就从这里开始。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!











