18.06 第 9 讲:线性无关、基与维数
- 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 给四个词下了定义:线性无关、张成、基、维数。我把四个词都翻译成了同一个操作:把向量放进矩阵的列,算秩,找零空间。固定种子取 1000 个随机的 100 × 100 矩阵,1000 个全是满秩,也就是“随机向量几乎总是无关”;而在另一头,我人为造了一组只差 的相关向量,matrix_rank 判它们是秩 3,也就是“无关”。这两个数字合起来,就是这一讲的数学定义和浮点数之间的距离。
视频:Lecture 9: Independence, basis, and dimension(OCW 页面与字幕) 教材:《Introduction to Linear Algebra》第 6 版 §3.4 Independence, Basis, and Dimension 前置:第 8 讲:解 Ax = b,行最简形 R 一句话:把向量放进矩阵的列,它们无关当且仅当零空间只有零向量;列空间的维数是秩 ,零空间的维数是 。
- 开头他先回顾“未知数比方程多,零空间里一定有非零向量”,这一段是整讲的伏笔,值得认真听。
- 讲无关的那一段( 和 、含零向量、平面里的三个向量)很短,本篇第一节已经用代码算过,可以倍速。
- 他在黑板上反复追问“给我另一组基”,那一段看一遍就行,本篇第二、三节有对应的代码。
- 最后三分钟是零空间的维数,两个特解就是零空间的基,这是下一讲的预告,别漏。
线性无关:看零空间
他先说了一条上一讲留下的事实: 是 的矩阵,如果 (未知数比方程多),那么 一定有非零解。理由是消元之后主元最多 个,至少剩下 个自由变量,自由变量可以随便取 1,再回代解出主变量。
线性无关是什么? 一堆向量 ,如果
除了所有 都是 0 之外别无解,它们就线性无关;若还有别的 能凑出零向量,它们就线性相关。他特地强调:说的是“一堆向量”无关,不说“一个矩阵”无关。
接着他举了三个例子: 和 (两份第一个减去第二个就是零,相关)、 和零向量(零向量那一份随便取几都行,“只要里面有零向量,无关就死了”)、平面里的三个向量(必然相关)。第三个例子里他是这样看的:把三个向量放进 的三列, 是 ,列比行多,零空间里一定有非零的 ,这个 就是“往 走几步,往 走几步,再往 退几步,回到原点”。
这一下就把定义翻译成了矩阵语言:
- 列无关 没有自由变量 秩 。
- 列相关 零空间里有非零向量 有自由变量 。
我按字幕里他随手画的数取 、、(字幕是语音转写,“two and a half, minus one”我就照字面取了,他自己也说没画准)。下面的脚本做三件事:判三个向量是否无关,找出那个凑出零的 ,再把三种“一眼就相关”的情形跑一遍。零空间向量我用 SVD 的最后一个右奇异向量得到,这个办法后面几讲会解释,现在只当它是“零空间里的一个单位向量”:
import numpy as np
def null_vector(A: np.ndarray) -> np.ndarray: """返回 A 的零空间里的一个单位向量(A 的列相关时才有意义)。""" _, _, Vt = np.linalg.svd(A) return Vt[-1]
def main() -> None: np.set_printoptions(precision=4, suppress=True)
# 平面里的三个向量:把它们放进 A 的三列,A 是 2 x 3 v1 = np.array([2.0, 1.0]) v2 = np.array([1.0, 2.0]) v3 = np.array([2.5, -1.0]) A = np.column_stack([v1, v2, v3]) print("A 的形状:", A.shape, ",秩 =", np.linalg.matrix_rank(A)) print("独立的条件是秩 = 列数 3:", np.linalg.matrix_rank(A) == 3)
# 列比行多,零空间里一定有非零向量 c c = null_vector(A) print("零空间里的 c =", c) print("c1 v1 + c2 v2 + c3 v3 =", A @ c)
# 只取前两个向量,秩 = 2 = 列数,独立 print("v1, v2 的秩:", np.linalg.matrix_rank(A[:, :2]))
# 三种一眼就相关的情形:v 与 2v,含零向量 v = np.array([2.0, 1.0]) pairs = { "v 与 2v": np.column_stack([v, 2 * v]), "v 与零向量": np.column_stack([v, np.zeros(2)]), "v1 与 v2": np.column_stack([v1, v2]), } for name, M in pairs.items(): r = np.linalg.matrix_rank(M) print(f"{name}:秩 = {r},列数 = {M.shape[1]},独立:{r == 2}")
if __name__ == "__main__": main()A 的形状: (2, 3) ,秩 = 2独立的条件是秩 = 列数 3: False零空间里的 c = [-0.7428 0.5571 0.3714]c1 v1 + c2 v2 + c3 v3 = [ 0. -0.]v1, v2 的秩: 2v 与 2v:秩 = 1,列数 = 2,独立:Falsev 与零向量:秩 = 1,列数 = 2,独立:Falsev1 与 v2:秩 = 2,列数 = 2,独立:True 的矩阵秩最多是 2,所以三列不可能无关,这是“列比行多”的直接后果。c 的三个分量满足 ,右边打印出来的 [ 0. -0.] 就是验证(-0. 是浮点数的负零,不是错误)。把 同时除以 0.3714,得到 ,你可以手算验一遍:第一个分量 ,第二个 。
张成与基:不多不少
张成是什么? 一堆向量张成一个空间,意思是这个空间就是它们所有线性组合的集合。他说这个词其实早就用过了:矩阵的列张成列空间。他补了一句:这堆向量张成的空间是包含它们的最小空间,因为任何含有这些向量的空间都必须含有它们的所有组合。
单看张成不够,列可能有冗余;单看无关也不够,向量可能太少。基是什么? 同时满足两条:无关,并且张成这个空间。他的说法是“刚刚好”:少一个张不满,多一个就相关。这有点像点菜,少一道吃不饱,多一道吃不完,只有刚好的那一桌才既不饿也不浪费。往后每次问到子空间,他都会问“给我一组基”,因为基就是对这个子空间的完整描述。
他的第一个例子是 。最先想到的基是 、、 轴方向的三个单位向量,也就是单位矩阵的三列,零空间只有零向量,所以无关。第二个例子,他从 和 开始:两个向量无关,但张不满 。要补第三个。补 是个“失误”,因为它恰好是前两个之和,躺在同一个平面里。补 呢?他说“希望这个行”,然后问:如果我挑的是别的数,比如 ,我怎么知道?答案是放进矩阵的列,做消元,看有没有自由变量;对方阵来说,等价于矩阵可逆。
我把这三个候选逐个交给 NumPy,结果和字幕里的猜测不太一样:
import numpy as np
def main() -> None: np.set_printoptions(precision=4, suppress=True)
# R^3 的第一组基:单位矩阵的三列 print("单位矩阵的秩:", np.linalg.matrix_rank(np.eye(3)))
# 只有两个向量:独立,但张不满 R^3 B2 = np.array([[1.0, 2.0], [1.0, 2.0], [2.0, 5.0]]) print("(1,1,2) 与 (2,2,5) 的秩:", np.linalg.matrix_rank(B2))
# 第三个向量逐个试:秩 = 3 才是基(方阵时等价于 det 非零) for third in ([3.0, 3.0, 7.0], [3.0, 3.0, 8.0], [5.0, 7.0, -14.0]): M = np.column_stack([B2, third]) r = np.linalg.matrix_rank(M) print(f"补 {third}:秩 = {r},det = {np.linalg.det(M):.4f}")
# 前两个向量的第一、二个分量总相等,它们张成的平面是 x = y # (3, 3, 8) 也满足 x = y,所以它还在这个平面里 print("B2 的两列满足 x = y:", np.allclose(B2[0], B2[1]))
# 补 (5, 7, -14) 得到一组基:任意向量都有唯一的坐标 good = np.column_stack([B2, [5.0, 7.0, -14.0]]) x = np.array([1.0, -2.0, 3.0]) coeff = np.linalg.solve(good, x) print("x 在这组基下的坐标:", coeff) print("坐标重新组合回 x:", np.allclose(good @ coeff, x))
if __name__ == "__main__": main()单位矩阵的秩: 3(1,1,2) 与 (2,2,5) 的秩: 2补 [3.0, 3.0, 7.0]:秩 = 2,det = 0.0000补 [3.0, 3.0, 8.0]:秩 = 2,det = 0.0000补 [5.0, 7.0, -14.0]:秩 = 3,det = -2.0000B2 的两列满足 x = y: Truex 在这组基下的坐标: [ 78.5 -35. -1.5]坐标重新组合回 x: True也是相关的:前两个向量的第一、第二个分量都相等,它们张成的平面就是 ,而 的前两个分量也相等,所以它同样躺在这个平面里。这是 Strang 自己挑错了数字:他说“希望 3 3 8 可以”,课后有同学指出来,他在 第 10 讲 开头更正了。这个“挑数字挑错了”的插曲反而把他想说的事演示了:肉眼挑,十有八九会翻车,要用矩阵检验。(我这里再试一次运气, 通过,行列式是 。)
补上 之后,方阵 good 可逆,任意 都能唯一地写成三列的组合。随手取的 在这组基下的坐标是 ,系数不小,我猜是因为这三个向量彼此并不“垂直”,拼一个普通的向量得靠大系数互相抵消(我没有算条件数去证实,这只是猜测)。基有好坏之分,后面讲正交基的时候会回来。
还有一个他强调了两次的事实:基不唯一。任何可逆的 矩阵的列都是 的一组基,有无穷多组。但所有的基有一个共同点:向量个数相同。
维数:基里有几个向量
维数是什么? 对一个空间,所有基含有的向量个数相同,这个数就是它的维数。 的每组基都有 3 个向量;某个子空间的一组基有 6 个向量,那它的所有基都是 6 个。他说这是“定义性”的:维数就是基的向量个数,它回答的是“这个空间有多大”。
这里有一个用词上的提醒,我觉得值得抄下来:
- 矩阵有秩,没有“维数”。
- 子空间有维数,没有“秩”。
- 秩是列空间的维数,所以说“列空间的维数”,不说“ 的维数”。
他说,用词对了,就说明概念对了。
他用的矩阵是一个 的例子:四列依次是 、、、。第三列是前两列之和,第四列重复第一列。问题是:四列张成列空间,但是否是基?不是,因为 份第一列、 份第二列、 份第三列、 份第四列加起来是零向量,零空间里有非零向量。
他的回答是:自然的基是主列,也就是第一、第二列。从左往右扫,第一列可以放进基,第二列也可以,第三列不能(它是前两列的组合),第四列也不能。所以秩是 2,主列有 2 个,列空间的维数也是 2:秩、主列个数、列空间维数是同一个数。然后他让大家说“另一组基”:第一、三列,第二、三列,第二、四列都行,甚至不是 的列的也行,比如 和 (后者是四列之和)。
最后是一个我觉得很实用的小定理:如果你已经知道空间的维数是 ,并且手里有 个无关的向量,它们自动就是基,张成是白送的。因为如果张不满,就还缺一个向量来补,那时候就会有 个无关向量,超过了维数。
这一节所有的断言,我用一个脚本一并验证。其中的“主列”和“特解”都是手写的(主列:从左到右,加入这一列使秩增加,它就是主列;特解:自由变量取 1,其余自由变量取 0,再解主变量),用 np.linalg.matrix_rank 对照:
import numpy as np
def pivot_columns(A: np.ndarray) -> list[int]: """从左到右:这一列让秩增加,就是主列。""" pivots: list[int] = [] for j in range(A.shape[1]): if np.linalg.matrix_rank(A[:, pivots + [j]]) > len(pivots): pivots.append(j) return pivots
def special_solutions(A: np.ndarray, pivots: list[int]) -> np.ndarray: """每个自由列取 1、其余自由列取 0,再解出主变量。""" n = A.shape[1] free = [j for j in range(n) if j not in pivots] N = np.zeros((n, len(free))) for k, j in enumerate(free): N[j, k] = 1.0 N[pivots, k], *_ = np.linalg.lstsq(A[:, pivots], -A[:, j], rcond=None) return N
def main() -> None: np.set_printoptions(precision=4, suppress=True)
# Strang 的矩阵:四列依次是 (1,1,1)、(2,1,2)、(3,2,3)、(1,1,1) A = np.array( [ [1.0, 2.0, 3.0, 1.0], [1.0, 1.0, 2.0, 1.0], [1.0, 2.0, 3.0, 1.0], ] ) m, n = A.shape r = np.linalg.matrix_rank(A) print("A =") print(A) print(f"m = {m}, n = {n}, 秩 r = {r}")
# 列空间:主列就是一组基,维数 = 秩 pivots = pivot_columns(A) print("主列(从 0 数起):", pivots, ",列空间的维数 =", len(pivots))
# 零空间:特解就是一组基,维数 = n - r N = special_solutions(A, pivots) print("特解矩阵 N(每列一个特解):") print(N) print("A @ N = 0:", np.allclose(A @ N, 0)) print( "零空间的维数 n - r =", n - r, ",N 的秩 =", np.linalg.matrix_rank(N) )
# 他说的第一个组合:-1 份第一列,-1 份第二列,1 份第三列,0 份第四列 c = np.array([-1.0, -1.0, 1.0, 0.0]) print("A @ (-1, -1, 1, 0) =", A @ c)
# 另一组基:不是 A 的列,但在列空间里。7 5 7 是四列之和 B = np.column_stack([[2, 2, 2], [7, 5, 7]]).astype(float) print("B 的秩:", np.linalg.matrix_rank(B)) print( "B 的列都在列空间里:", np.linalg.matrix_rank(np.hstack([A, B])) == r ) print("四列之和 =", A @ np.ones(4))
if __name__ == "__main__": main()A =[[1. 2. 3. 1.] [1. 1. 2. 1.] [1. 2. 3. 1.]]m = 3, n = 4, 秩 r = 2主列(从 0 数起): [0, 1] ,列空间的维数 = 2特解矩阵 N(每列一个特解):[[-1. -1.] [-1. 0.] [ 1. 0.] [ 0. 1.]]A @ N = 0: True零空间的维数 n - r = 2 ,N 的秩 = 2A @ (-1, -1, 1, 0) = [0. 0. 0.]B 的秩: 2B 的列都在列空间里: True四列之和 = [7. 5. 7.]零空间的维数是 n - r
最后几分钟他转向零空间。刚才那个非零向量 只是零空间里的一个向量,零空间里还有别的。自然的选择是:第四列是自由列,令这个自由变量为 1、另一个自由变量(第三列)为 0,问第四列是不是主列的组合。是的,它就是第一列,所以 在零空间里。这两个向量正是上一讲的特解:每个自由变量轮流取 1,其他自由变量取 0。
它们无关,而且张成整个零空间,所以是零空间的一组基,零空间的维数是 2。更一般地: 列里有 个主列,剩下 个自由列,每个自由列给一个特解,因此
上面代码块的输出正对着这两个公式:、、,主列是第 0、1 列(从 0 数起),特解矩阵 N 的两列正是 和 ,A @ N 全零, 的秩是 2。零空间里的向量就是“这些列相关的方式”:每一个特解告诉你,哪几列怎么组合能得零。
浮点数里的“几乎无关”
定义是干净的:要么无关,要么相关。但 np.linalg.matrix_rank 判的是数值秩,它拿奇异值和一个阈值比(默认阈值约为 ,),低于阈值的奇异值当成 0。所以“相关”在浮点数里是有一个模糊带的。下面的脚本做两个实验。第一个:固定种子取随机向量,看它们是不是几乎总是无关(他在第 1 讲说过“MATLAB 的随机矩阵几乎一定可逆”);并且验证 个 维向量必相关。第二个:第三列取前两列之和,再加上噪声,看噪声多小时 matrix_rank 会被“骗过去”:
import numpy as np
def main() -> None: np.set_printoptions(precision=4, suppress=True) rng = np.random.default_rng(1806)
# 随机取 n 个 n 维向量:几乎总是独立(秩 = n) for n in (3, 10, 100): trials = 1000 full = sum( np.linalg.matrix_rank(rng.standard_normal((n, n))) == n for _ in range(trials) ) print(f"n = {n:3d}:{trials} 次里有 {full} 次秩为 n")
# 取 n + 1 个 n 维向量:必相关,零空间至少一维 n = 5 M = rng.standard_normal((n, n + 1)) print("5 维里取 6 个向量,秩 =", np.linalg.matrix_rank(M)) _, s, Vt = np.linalg.svd(M) c = Vt[-1] print("‖M c‖ =", f"{np.linalg.norm(M @ c):.2e}")
# 浮点数里的“相关”:第三列 = 前两列之和,再加一点点噪声 base = rng.standard_normal((4, 2)) third = base[:, 0] + base[:, 1] for eps in (0.0, 1e-16, 1e-12, 1e-8, 1e-4): noise = eps * rng.standard_normal(4) M = np.column_stack([base, third + noise]) s = np.linalg.svd(M, compute_uv=False) print( f"噪声 {eps:7.0e}:最小奇异值 = {s[-1]:.2e}," f"秩 = {np.linalg.matrix_rank(M)}" )
if __name__ == "__main__": main()n = 3:1000 次里有 1000 次秩为 nn = 10:1000 次里有 1000 次秩为 nn = 100:1000 次里有 1000 次秩为 n5 维里取 6 个向量,秩 = 5‖M c‖ = 4.79e-16噪声 0e+00:最小奇异值 = 9.16e-17,秩 = 2噪声 1e-16:最小奇异值 = 2.18e-16,秩 = 2噪声 1e-12:最小奇异值 = 9.42e-13,秩 = 3噪声 1e-08:最小奇异值 = 9.92e-09,秩 = 3噪声 1e-04:最小奇异值 = 5.54e-05,秩 = 3前三行:随机取向量,在 三种规模下各试 1000 次,每一次都是满秩,随机向量“几乎总是无关”不是夸张。第四、五行:5 维空间里的 6 个向量,秩最多 5,所以必相关,找到的 让 ,也就是舍入误差的水平。
最后五行是我觉得最有意思的。第三列是前两列的精确之和时(噪声 0),最小奇异值是 ,判相关,对的。噪声只有 时最小奇异值是 ,还在阈值之下,判相关。可是噪声涨到 ,最小奇异值 已经高于阈值,matrix_rank 就判秩 3,也就是“无关”了。严格地说,这三列在数学上是无关的(噪声不为零),所以 NumPy 没有错。但如果这个噪声只是测量误差,那么它判的“无关”就没有意义。
我的结论是:数学里的无关是一个二选一,数值里的“秩”是一个带阈值的判断,阈值怎么取要看这个噪声是不是你关心的东西。后面讲 SVD 时,我会换一个角度处理这件事:奇异值是多少,比“秩是几”携带的信息多得多。(所以我在日常里更愿意看最小奇异值,而不是只看 matrix_rank 的那个整数。)
这一讲算是把前八讲反复出现的词都落了地:消元找主元,主元是几个,秩就是几;自由变量是几个,零空间就是几维。下一讲要把列空间、零空间再配上它们的两个“转置版本”,凑齐四个基本子空间,并把它们的维数 、、、 一次说完,见 18.06 第 10 讲:四个基本子空间。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!











