跳轉到

2.1 矩陣即變換: \(A\mathbf{v}\) 的幾何意義#

本節目標#

  • 把「矩陣」從一格格的數字,重新看成 空間的變換(function:吃進向量、吐出向量)
  • 理解線性變換的兩條規則:保持加法與純量乘
  • 掌握關鍵事實:矩陣的每一行,就是基底向量 \(\mathbf{e_1}, \mathbf{e_2}\) 變換後的像
  • 用第 1 章的 linalg_viz 工具箱,親眼看見單位方格網被矩陣「剪」成斜的
  • 會用 NumPy 的 A @ v 對向量做變換

2.1.1 從「數字格子」到「空間機器」#

高中教你的矩陣長這樣:

\[ A = \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix} \]

一堆數字,乘法規則靠背。但換個角度:

矩陣是一部機器:餵它一個向量 \(\mathbf{v}\) ,它吐出另一個向量 \(A\mathbf{v}\) 。

輸入 \(\mathbf{v} = \begin{bmatrix} 2 \\ 1 \end{bmatrix}\) ,輸出:

\[ A\mathbf{v} = \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 2 \\ 1 \end{bmatrix} = \begin{bmatrix} 1\cdot 2 + 1\cdot 1 \\ 0\cdot 2 + 1\cdot 1 \end{bmatrix} = \begin{bmatrix} 3 \\ 1 \end{bmatrix} \]

向量被「推」了。整個平面上所有的點同時被推 —— 這就是 變換。

2.1.2 什麼是「線性」變換?#

不是所有變換都配得上矩陣。矩陣只能表達 線性 變換,它必須遵守兩條規則:

  1. 保持加法: \(T(\mathbf{u} + \mathbf{v}) = T(\mathbf{u}) + T(\mathbf{v})\)
  2. 保持純量乘: \(T(c\,\mathbf{v}) = c\,T(\mathbf{v})\)

幾何上這意味著:

  • 原點不動( \(T(\mathbf{0}) = \mathbf{0}\) )
  • 直線仍是直線(不會彎)
  • 等距的點變換後仍等距(格子不會被不均勻地拉扯)

旋轉、鏡射、剪切、縮放都遵守這兩條;平移 不遵守(平移會動到原點),所以純矩陣表達不了平移 —— 這要到第 8 章用「齊次座標」偷偷解決。

用 NumPy 直接驗證兩條規則:

import numpy as np

A = np.array([[1., 1.],
              [0., 1.]])
u = np.array([2., 1.])
v = np.array([-1., 3.])

lhs = A @ (u + v)          # T(u + v)
rhs = A @ u + A @ v        # T(u) + T(v)
print(np.allclose(lhs, rhs))   # True:加法保持

lhs = A @ (2.5 * v)        # T(c v)
rhs = 2.5 * (A @ v)        # c T(v)
print(np.allclose(lhs, rhs))   # True:純量乘保持

2.1.3 最關鍵的一句話:矩陣的行就是 \(\mathbf{e_1}, \mathbf{e_2}\) 的像#

把 \(\mathbf{e_1} = \begin{bmatrix} 1 \\ 0 \end{bmatrix}\) 、 \(\mathbf{e_2} = \begin{bmatrix} 0 \\ 1 \end{bmatrix}\) 餵進矩陣:

\[ A\mathbf{e_1} = \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix} 1 \\ 0 \end{bmatrix} \qquad A\mathbf{e_2} = \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 0 \\ 1 \end{bmatrix} = \begin{bmatrix} 1 \\ 1 \end{bmatrix} \]

看到了嗎?** \(A\mathbf{e_1}\) 就是 \(A\) 的第一行, \(A\mathbf{e_2}\) 就是 \(A\) 的第二行**。一般地:

\[ A = \begin{bmatrix} | & | \\ T(\mathbf{e_1}) & T(\mathbf{e_2}) \\ | & | \end{bmatrix} \]

矩陣不需要背,它是「基底向量被丟去哪裡」的完整紀錄。 知道 \(\mathbf{e_1}, \mathbf{e_2}\) 的下場,就知道整個平面的下場 —— 因為任何向量都是它們的線性組合(1.3 節)。

2.1.4 雙重觀點: \(A\mathbf{v}\) 是「行的線性組合」#

同一個計算 \(A\mathbf{v}\) ,有兩種讀法:

觀點一(逐列):每一列和 \(\mathbf{v}\) 做內積,得到輸出的每個分量。

觀點二(逐行):

\[ \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 2 \\ 1 \end{bmatrix} = 2 \begin{bmatrix} 1 \\ 0 \end{bmatrix} + 1 \begin{bmatrix} 1 \\ 1 \end{bmatrix} = \begin{bmatrix} 3 \\ 1 \end{bmatrix} \]

** \(A\mathbf{v}\) 就是「用 \(\mathbf{v}\) 的分量當係數,對 \(A\) 的行做線性組合」。**

觀點二是理解一切的鑰匙:變換後的向量落在「行的張成空間」裡。這句話會在第 4 章(張成、基底)、第 5 章(特徵向量)反覆出現。

2.1.5 動手畫:剪切變換把方格網變成什麼?#

用第 1.4 節建立的 linalg_viz 工具箱,畫出 \(A = \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix}\) 作用前後的單位方格網:

import numpy as np
import matplotlib.pyplot as plt
from linalg_viz import setup_axes, draw_grid_transform, draw_vectors

A = np.array([[1., 1.],
              [0., 1.]])

fig, ax = plt.subplots(figsize=(7, 7))
setup_axes(ax, xlim=(-1, 5), ylim=(-1, 4))
draw_grid_transform(ax, A, xlim=(-1, 5), ylim=(-1, 4))
draw_vectors(ax, {
    r"$\mathbf{e_1}$": np.array([1., 0.]),   # 變換前(虛線)
    r"$T(\mathbf{e_1})$": A @ np.array([1., 0.]),
    r"$\mathbf{e_2}$": np.array([0., 1.]),
    r"$T(\mathbf{e_2})$": A @ np.array([0., 1.]),
})
ax.set_title(r"Shear: $A = \begin{bmatrix}1&1\\0&1\end{bmatrix}$")
plt.show()

你會看到:

  • 淡色方格網是變換前的平面
  • 深色網格是變換後的平面:每一條水平線向右滑,滑的距離等於它的高度( \(y\) 越大滑越多)
  • \(\mathbf{e_1}\) 沒動( \(A\mathbf{e_1} = \mathbf{e_1}\) ,第一行是 \((1,0)\) )
  • \(\mathbf{e_2}\) 被推成 \((1, 1)\) (第二行)—— 這就是「剪」的來源:像推倒一疊撲克牌

試著把 \(A\) 換成 \(\begin{bmatrix} 1 & 0 \\ 1 & 1 \end{bmatrix}\) (垂直剪切)、 \(\begin{bmatrix} 2 & 0 \\ 0 & 1 \end{bmatrix}\) (水平拉伸),重跑一次,觀察行向量如何「指揮」整個平面。

2.1.6 NumPy 實戰:A @ v#

import numpy as np

A = np.array([[1., 1.],
              [0., 1.]])
v = np.array([2., 1.])

print(A @ v)            # [3. 1.]   矩陣乘向量
print(A @ np.eye(2))    # 驗證:乘單位矩陣不變
# 同時變換一堆向量(每行一個向量)——一次算整個平面!
V = np.array([[2., -1., 0.],
              [1.,  3., 2.]])
print(A @ V)
# [[3. 2. 2.]
#  [1. 3. 2.]]

注意 A @ V 一次變換三個向量:矩陣乘矩陣,其實就是「對每個行向量各做一次 \(A\mathbf{v}\) 」。這為下一節的矩陣乘法鋪路。

flowchart LR
    v["向量 v"] --> M["機器 A"] --> w["新向量 Av"]
    e1["e1"] --> M
    e2["e2"] --> M
    subgraph 紀錄
      col1["第一行 = A e1"]
      col2["第二行 = A e2"]
    end
    M -.記錄下場.-> 紀錄

小結與練習#

本節重點

  • 矩陣是 線性變換:保持加法與純量乘,原點不動、直線仍直
  • \(A\) 的第 \(j\) 行就是 \(T(\mathbf{e_j})\) :矩陣是基底向量的「下場紀錄表」
  • \(A\mathbf{v} = v_1(\text{第1行}) + v_2(\text{第2行})\) :矩陣乘向量 = 行的線性組合
  • A @ v 一行程式,A @ V 一次變換整批向量

練習

  1. 寫下矩陣 \(B\) ,使 \(B\mathbf{e_1} = \begin{bmatrix} 0 \\ 2 \end{bmatrix}\) 、 \(B\mathbf{e_2} = \begin{bmatrix} -1 \\ 0 \end{bmatrix}\) ,用 linalg_viz 畫出 \(B\) 的網格圖。這個變換做了什麼(旋轉?鏡射?)?
  2. 計算 \(A\mathbf{v}\) ( \(A\) 為剪切矩陣, \(\mathbf{v} = (3, -2)\) ),先用「行的線性組合」心算,再用 NumPy 驗證。
  3. 證明(用 NumPy 隨機向量測試即可):若 \(A\) 是任意 \(2\times2\) 矩陣,則 \(A(\mathbf{0}) = \mathbf{0}\) 。
  4. 挑戰:矩陣 \(C = \begin{bmatrix} 1 & 2 \\ 2 & 4 \end{bmatrix}\) 把整個平面壓成一條直線。畫出 \(C\) 的網格圖,並觀察它的兩行有什麼關係(提示:第 3 章的「線性相依」)。