3.3 秩、零空間與解空間:線性相依的真相#
本節目標#
- 理解 秩(rank):矩陣真正攜帶的「資訊維度」
- 會用
np.linalg.matrix_rank計算秩,並將線性相依/獨立與方程組的解連起來 - 定義並計算 零空間 \(N(A)=\{\mathbf{x}:A\mathbf{x}=\mathbf{0}\}\) ,用
scipy.linalg.null_space - 掌握秩與解的個數之間的完整對照表
- 畫圖親眼看見零空間:一個 \(3\times 2\) 矩陣如何把平面壓扁
一、秩:變換後還剩幾維?#
第 2 章看過:有些變換會把平面壓成一條線、甚至壓成一個點。秩 就是替「壓扁程度」量化的一個數:
\(\operatorname{rank}(A)\) = \(A\) 的行向量中,線性獨立的那幾個的數量 = 變換後像空間的 維度。
- \(2\times 2\) 矩陣、 \(\operatorname{rank}=2\) :平面被完整保留(可逆, \(\det\neq 0\) )。
- \(\operatorname{rank}=1\) :平面被壓成一條過原點的直線。
- \(\operatorname{rank}=0\) :只剩零矩陣,整個平面被壓成原點。
import numpy as np
A_full = np.array([[2.0, 1.0],
[1.0, -1.0]])
A_sing = np.array([[1.0, 2.0],
[2.0, 4.0]]) # 第二行是第一行的 2 倍
A_zero = np.zeros((2, 2))
print(np.linalg.matrix_rank(A_full)) # 2:行向量獨立,平面保住
print(np.linalg.matrix_rank(A_sing)) # 1:壓成直線
print(np.linalg.matrix_rank(A_zero)) # 0:壓成點
一個關鍵恆等式(本書最重要的「守恆律」之一,第 4.3 節會推廣成秩–零化度定理):
被壓扁的資訊沒有消失,它們全部擠進了 零空間。
二、線性相依在方程組裡的意義#
矩陣的行向量線性相依 ⟺ 某一行是其他行的組合 ⟺ 變換丟失維度。反映在 \(A\mathbf{x}=\mathbf{b}\) 上:
- 行獨立(滿秩方陣):任何 \(\mathbf{b}\) 要嘛恰好一個解、要嘛不可達(非方陣時)——沒有「多餘的方向」。
- 行相依:存在非零的 \(\mathbf{x}\) 使 \(A\mathbf{x}=\mathbf{0}\) 。於是只要 \(\mathbf{x}_0\) 是 \(A\mathbf{x}=\mathbf{b}\) 的一個解, \(\mathbf{x}_0+\mathbf{v}\) ( \(\mathbf{v}\in N(A)\) )也是解:
相依 = 出現「隱形移動」:沿著零空間的方向平移,機器的輸出不變,所以解一多就是一整個子空間。
三、零空間:哪些輸入會被送進原點?#
定義:
它是「變換的盲點」:所有被 \(A\) 無情壓到原點的向量。幾何事實:零空間永遠是 過原點的子空間(直線、平面……),且 \(A\mathbf{x}=\mathbf{b}\) 有解時,全部解 = 一個特解 + 整個零空間。
用 SciPy 計算:
from scipy.linalg import null_space
A = np.array([[1.0, 2.0],
[2.0, 4.0]]) # 秩 1
N = null_space(A)
print(N) # 2×1 向量,例如 [-0.894, 0.447]
print(np.allclose(A @ N, 0)) # True:果然被送進原點
# 驗證「解 + 零空間 = 全部解」
b = np.array([1.0, 2.0]) # b 剛好在像空間上
x0 = np.array([1.0, 0.0]) # 特解:x + 2y = 1 的一個解
for t in [-2, 0, 3]:
x = x0 + t * N[:, 0]
print(np.allclose(A @ x, b)) # 全部 True
零空間的維度(叫 零化度,nullity)也可以用秩倒算: \(n-\operatorname{rank}(A)=2-1=1\) ,所以 \(N(A)\) 是一條直線 —— null_space 回傳的矩陣有 1 個行向量,正是這條直線的方向。
四、秩與解數的完整對照表#
設 \(A\) 是 \(m\times n\) , \(r=\operatorname{rank}(A)\) , \(\bar{r}=\operatorname{rank}([A\,|\,\mathbf{b}])\) :
| 情形 | 條件 | \(A\mathbf{x}=\mathbf{b}\) 的解 | \(A\mathbf{x}=\mathbf{0}\) 的解 |
|---|---|---|---|
| 滿秩方陣 | \(r=n\) (且方陣) | 唯一解 | 只有 \(\mathbf{0}\) |
| 相依且可達 | \(r=\bar{r}<n\) | 無窮多解( \(\dim N(A)=n-r\) 個自由度) | 無窮多解 |
| 相依且不可達 | \(r<\bar{r}\) | 無解 | 仍只有零空間那套 |
記憶口訣:
- ** \(\mathbf{b}\) 進得來嗎?** 看 \(\mathbf{b}\) 是否在像空間(等價於 \(r=\bar{r}\) )→ 決定「有沒有解」。
- 進得來之後有幾個? 看 \(\dim N(A)=n-r\) → 決定「一個還是一窩」。
五、畫圖:看見零空間#
用一個 \(3\times 2\) 矩陣把 \(\mathbb{R}^2\) 壓進 \(\mathbb{R}^3\) 。若秩為 2,整個平面被搬到 3D 空間中的一個平面(這時零空間只有 \(\{\mathbf{0}\}\) );把秩降成 1,平面就被壓成一條線,而「被壓掉的那個方向」就是零空間。
import matplotlib.pyplot as plt
from linalg_viz import plot_vectors
A = np.array([[1.0, 2.0], # 3×2:把 2D 輸入映射到 3D
[2.0, 4.0], # 第二行 = 2 × 第一行 → 秩 1
[-1.0, -2.0]])
N = null_space(A) # 形狀 (2, 1)
print(np.linalg.matrix_rank(A)) # 1
fig = plt.figure(figsize=(11, 5))
# ---- 左圖:輸入空間 R^2,標出零空間直線 ----
ax1 = fig.add_subplot(1, 2, 1)
t = np.linspace(-2, 2, 50)
line = np.outer(N[:, 0], t) # 零空間直線上的一串點
ax1.plot(line[0], line[1], "g-", lw=2, label="N(A)(零空間)")
ax1.scatter(*N[:, 0], color="g", s=40)
ax1.axhline(0, color="gray", lw=0.5); ax1.axvline(0, color="gray", lw=0.5)
ax1.set_title("輸入空間:整條綠線都會被壓到原點")
ax1.set_aspect("equal"); ax1.legend(); ax1.grid(True)
# ---- 右圖:像空間 R^3,整個 R^2 被壓成一條線 ----
ax2 = fig.add_subplot(1, 2, 2, projection="3d")
grid = np.stack(np.meshgrid(np.linspace(-1, 1, 8),
np.linspace(-1, 1, 8))).reshape(2, -1)
img = A @ grid # 所有輸入的像
ax2.scatter(*img, s=5, alpha=0.3)
plot_vectors(ax2, [A[:, 0]], ["$Aa_1$(像空間其實只有這條線)"])
ax2.set_title("輸出空間:R^2 被壓成 R^3 中的一條線")
plt.tight_layout(); plt.show()
# 驗證:零空間直線上每個點都被送進原點
print(np.allclose(A @ (line), 0)) # True
左圖的綠線是「盲點」:無論你沿著它走多遠,右圖的紅點都紋風不動地黏在原點。這就是 \(A\mathbf{x}=\mathbf{0}\) 有非零解的畫面,也是「無窮多解」的幾何根源。
六、順手一提:秩的數值陷阱#
matrix_rank 靠奇異值(第 7 章主角)判斷,預設容忍微小誤差。手算理論上是整數的秩,浮點世界裡可能是「接近但不等於」:
B = np.array([[1.0, 2.0],
[2.0, 4.0]])
B[1, 1] += 1e-15 # 微小擾動
print(np.linalg.matrix_rank(B)) # 仍給 1(容忍)
print(np.linalg.matrix_rank(B, tol=1e-20)) # 2(逼它較真)
「幾乎相依」的矩陣是最危險的一族 —— 條件數的故事,第 9 章見。
小結與練習#
- \(\operatorname{rank}(A)\) = 獨立行向量數 = 像空間維度 = 變換沒弄丟的維度數。
- 齊次解 \(A\mathbf{x}=\mathbf{0}\) 的全集是零空間 \(N(A)\) ;非齊次有解時,全部解 = 特解 + \(N(A)\) 。
- 秩–零化度: \(n = \operatorname{rank}(A) + \dim N(A)\) ;解的個數由 \(r\) 、 \(\bar{r}\) 、 \(n\) 三者關係決定。
np.linalg.matrix_rank與scipy.linalg.null_space是本節的兩把工具。
練習:
- 對第四節表格的每一種情形,各構造一個 \(3\times 3\) 的具體例子( \(A,\mathbf{b}\) ),用
matrix_rank與null_space驗證你的分類。 - 求 \(A=\begin{bmatrix}1&2&3\\ 2&4&6\end{bmatrix}\) 的秩與零空間,畫出 \(N(A)\) ,並解釋為什麼 \(\dim N(A)=2\) 。
- 取本節的 \(3\times 2\) 矩陣 \(A\) 與像空間內的 \(\mathbf{b}\) ,找出 兩個 相差的解 \(\mathbf{x}_1\neq\mathbf{x}_2\) ,驗證 \(\mathbf{x}_1-\mathbf{x}_2 \in N(A)\) 。
- 隨機生成 1000 個 \(4\times 4\) 的 0/1 矩陣,統計秩為 4、3、2 的比例,思考:為什麼「隨機」幾乎總是滿秩?