跳转至

讲解稿 · 第02章 第04节 · 线性变换

口播时长:约 15–20 分钟|建议语速:中速偏慢,公式处停两拍|字数:约 3800 字


开场钩子

嘿,先做一件事:把手机拿起来,随手拍一张照片,然后在相册里点"编辑",把它旋转 90 度。

你看,图像整齐地转过去了。像素没错乱、直线还是直线、平行的边还平行。

我问你——手机在这一瞬间到底干了啥?

它没有一个像素一个像素地问"你要去哪儿"。它做的事只有一件:把一张矩阵,套在你照片的每一个像素坐标上。一次矩阵乘法,全部像素就到了新位置。

这就是这一节要讲的东西——线性变换。你今天用过的每一个滤镜、每一次拖拽缩放、每一款游戏里角色的转身,背后都是同一个动作:拿一个矩阵,去乘一个向量。

更关键的是:现在最火的那些大模型,Gemini、ChatGPT、Claude、DeepSeek——它们之所以叫 Transformer,是因为整个网络的骨头,就是一层一层的线性变换。数据一路穿过去,穿一层就被变换一次。

所以这一节,你别只当是学"矩阵在几何上代表什么"。你在学的是从图像编辑器一路通到大模型的同一个动作。

扶稳了,我们开始。


复习昨日 & 今日路线

先花 30 秒把上下文对齐。

昨天我们讲了 §03 矩阵运算——你会加、会乘、知道 \(AB \ne BA\)。再往前 Ch01 §05,我们讲了基变换:换一组坐标看同一个向量,口诀是——

"\(P\) 的列是新基,\(P\) 把新坐标搬回旧描述。"

今天这一节,我们把这两个东西钉在一起:矩阵不只是数字表,矩阵本身就是一个变换。你乘一个矩阵,就是在对向量施加一次几何动作。

下一节 §05 我们会讲矩阵分解——把一个复杂矩阵拆成几个简单变换的连乘,SVD、LU、QR 都是干这个的。所以今天你先把"矩阵 = 变换"这个直觉锁死,下一节拆解才有得拆。

好,进正题。


核心概念一 · 什么样的映射才配叫"线性"(约 3 分钟)

先给直觉。

想象一张网格纸,横竖都是直线,格子都是正方形。现在有一台"变形机器",你把网格纸塞进去,它出来的时候——

  • 直线还是直线(不能扭成弧);
  • 平行线还是平行(不能一边张开一边收拢);
  • 原点还在原点(网格中心那个点不能挪)。

只要这台机器满足这三条,我们就叫它线性变换 (linear transformation),也叫线性映射 (linear map)。

正式定义。线性变换 \(T : V \to W\) 是一个函数,把 \(V\) 里的向量映到 \(W\) 里的向量,并且满足下面这套公理。

好,这里到了 Ch02 第一次正式给公理,我给你三件套——每条公理都是"名字 + 大白话 + 反例",别背符号,背反例。

公理 1 · 加性 (additivity):\(T(\mathbf{u} + \mathbf{v}) = T(\mathbf{u}) + T(\mathbf{v})\)。

大白话:先把两个向量加起来再变换,跟分别变换完再加,结果一样。

反例:\(T(x) = x^2\) 不是线性的。为什么?\(T(1 + 1) = T(2) = 4\),但 \(T(1) + T(1) = 1 + 1 = 2\)。\(4 \ne 2\),加性破了。

公理 2 · 齐次性 (homogeneity):\(T(c\mathbf{u}) = c \, T(\mathbf{u})\)。

大白话:先缩放再变换,跟先变换再缩放,结果一样。缩放的因子可以"穿过"变换。

反例:\(T(x) = x + 1\) 不是线性的。\(T(2 \cdot 1) = T(2) = 3\),但 \(2 \cdot T(1) = 2 \cdot 2 = 4\)。\(3 \ne 4\),齐次破了。

公理 3 · 零映射 (maps zero to zero):\(T(\mathbf{0}) = \mathbf{0}\)。

大白话:原点必须待在原点,不许挪。

反例:平移(translation)不是线性的。若 \(T(\mathbf{x}) = \mathbf{x} + (3, 0)^\top\),那 \(T(\mathbf{0}) = (3, 0)^\top \ne \mathbf{0}\)。零点跑了,线性性直接破产。

顺便说一句,公理 3 其实是从前两条推出来的(把 \(c = 0\) 代进公理 2),但我们把它单列出来,是因为这条最直观、最容易用来一眼判断"这个变换是不是线性的"——先看原点动没动,动了就不是。

符号首现——今天要用到 \(T\) 这个符号,四件套走一遍。

\(T\) — 变换 (transformation):一个从向量空间到向量空间的函数,写作 \(T(\mathbf{v})\) 或 \(T\mathbf{v}\)。例子:\(T(x, y) = (2x + y,\ x + 2y)\) 是从 \(\mathbb{R}^2\) 到 \(\mathbb{R}^2\) 的一个线性变换。

你验证一下这个例子:\(T(\mathbf{0}) = (0, 0)\) ✓;\(T((1, 0) + (0, 1)) = T(1, 1) = (3, 3)\),而 \(T(1, 0) + T(0, 1) = (2, 1) + (1, 2) = (3, 3)\) ✓。三条公理都过。

一句话总结:线性变换 = 保持加法 + 保持缩放 + 原点不动。三件缺一,不是线性。


核心概念二 · 矩阵就是变换本身(约 2.5 分钟)

现在我要跟你说这一节最重要的一句话。

每一个线性变换,都可以写成一次矩阵乘法。矩阵不是"表示"变换——矩阵就是变换本身。

怎么理解?我们从一个观察出发。

在 \(\mathbb{R}^2\) 里,你随便一个向量 \(\mathbf{v} = (x, y)\),其实是 \(x \hat{\mathbf{i}} + y \hat{\mathbf{j}}\),其中 \(\hat{\mathbf{i}} = (1, 0)\)、\(\hat{\mathbf{j}} = (0, 1)\) 是标准基。

现在一个线性变换 \(T\) 来了,因为 \(T\) 保加法、保缩放,所以

\[T(\mathbf{v}) = T(x\hat{\mathbf{i}} + y\hat{\mathbf{j}}) = x \, T(\hat{\mathbf{i}}) + y \, T(\hat{\mathbf{j}})\]

看到没?只要我知道 \(T\) 把 \(\hat{\mathbf{i}}\) 和 \(\hat{\mathbf{j}}\) 送到哪里,剩下所有向量的去处就全定了。

那我把 \(T(\hat{\mathbf{i}})\) 摆成矩阵的第一列,把 \(T(\hat{\mathbf{j}})\) 摆成第二列,这个矩阵就完整刻画了 \(T\)。

数字例子。取 🟢

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

看第一列 \((2, 1)^\top\)——这告诉你 \(\hat{\mathbf{i}} = (1, 0)\) 被送到 \((2, 1)\)。看第二列 \((1, 2)^\top\)——\(\hat{\mathbf{j}} = (0, 1)\) 被送到 \((1, 2)\)。

现在拿个具体向量算:\(\mathbf{v} = (3, 4)\),套 \(A\) 上去:

\[A \mathbf{v} = 3 \cdot (2, 1) + 4 \cdot (1, 2) = (6 + 4,\ 3 + 8) = (10, 11)\]

这一步在黑板上,我会画:先把 \((3, 4)\) 拆成"三份 \(\hat{\mathbf{i}}\) + 四份 \(\hat{\mathbf{j}}\)",然后把 \(\hat{\mathbf{i}}\) 换成 \((2, 1)\)、\(\hat{\mathbf{j}}\) 换成 \((1, 2)\),三份加四份,得到 \((10, 11)\)。

记住这句口诀:矩阵的每一列 = 对应基向量被送到的位置。整章的几何直觉都靠它。

⏸️ 暂停思考 · 第一次

停一下。矩阵 $$ B = \begin{bmatrix} 0 & 1 \ 1 & 0 \end{bmatrix} $$ 在几何上干了什么? 提示:看看它的两列,\(\hat{\mathbf{i}}\) 跑哪去了?\(\hat{\mathbf{j}}\) 跑哪去了?把标准坐标系画出来,你就一眼看出来了。

(答案:\(\hat{\mathbf{i}}\) 跑到 \((0,1)\)、\(\hat{\mathbf{j}}\) 跑到 \((1,0)\)——两者交换。这就是沿直线 \(y = x\) 的反射。)


核心概念三 · 五种典型变换的形状(约 3.5 分钟)

现在我们把最常见的几种线性变换,一个一个过。你别死记矩阵长啥样,就记住"两列 = 基向量送去哪"。

🟢 旋转 (rotation)

想让 \(\hat{\mathbf{i}}\) 顺时针不动、转到 \((\cos\theta, \sin\theta)\);\(\hat{\mathbf{j}}\) 从 \((0, 1)\) 转到 \((-\sin\theta, \cos\theta)\)。摆成矩阵:

\[R(\theta) = \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix}\]

代 \(\theta = 90°\):\(\cos 90° = 0\)、\(\sin 90° = 1\),得到

\[R(90°) = \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}\]

验证:\(\hat{\mathbf{i}} = (1, 0)\) 送到 \((0, 1)\)(第一列),确实转了 90 度。

旋转矩阵有两个漂亮的性质:长度不变、行列式为 \(+1\)。

🟢 缩放 (scaling)

沿 \(x\) 轴拉 \(s_x\) 倍、沿 \(y\) 轴拉 \(s_y\) 倍:

\[S(s_x, s_y) = \begin{bmatrix} s_x & 0 \\ 0 & s_y \end{bmatrix}\]

数字例:\(S(2, 0.5)\) 把 \((1, 4)\) 送到 \((2, 2)\)。对角矩阵永远是一次缩放。当你在电脑上把图片长边缩到一半,就是在对每个像素乘 \(S(0.5, 0.5)\)。

🟢 反射 (reflection)

沿 \(x\) 轴照镜子——\(y\) 分量翻负号:

\[\text{Ref}_x = \begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}\]

\((3, 2)\) 变成 \((3, -2)\)。反射矩阵的行列式是 \(-1\),负号提醒你朝向翻了。旋转和反射合起来叫刚体变换——保距离、保角度,只是可能翻个身。

🟡 错切 (shearing)

想象一副印刷字,正体和斜体的差别就是错切。水平错切因子 \(k\):

\[\text{Sh}_x(k) = \begin{bmatrix} 1 & k \\ 0 & 1 \end{bmatrix}\]

含义:\(\hat{\mathbf{i}}\) 不动、\(\hat{\mathbf{j}}\) 从 \((0, 1)\) 挪到 \((k, 1)\)。\(k = 0.5\)、高度为 2 的点会向右滑 1。底不动,顶跑了。斜体字就是这样做出来的。

🔴 退化变换 (degenerate)

这是最有意思的一种:信息被压塌。看这个矩阵:

\[D = \begin{bmatrix} 1 & 2 \\ 2 & 4 \end{bmatrix}\]

两列 \((1, 2)\) 和 \((2, 4)\)——第二列是第一列的 2 倍。也就是说,\(\hat{\mathbf{i}}\) 和 \(\hat{\mathbf{j}}\) 变换后落在同一条直线上。整个二维平面被这个矩阵压塌成一条直线。

行列式为零,\(\det D = 1 \cdot 4 - 2 \cdot 2 = 0\)。信息永久丢失,这个变换没有逆。

生活里的例子:彩色图转灰度。RGB 三通道压到亮度一维,就是一次退化变换——你没法从灰度图恢复出原来的颜色。


核心概念四 · 平移为什么"不算"线性(约 2.5 分钟)

到这里你可能会问:那平移呢?我把整张图往右挪 3 格,是不是也是一种线性变换?

答案是——不是。

回想公理 3:\(T(\mathbf{0}) = \mathbf{0}\)。平移 \(T(\mathbf{x}) = \mathbf{x} + \mathbf{t}\) 把零向量送到了 \(\mathbf{t}\),只要 \(\mathbf{t} \ne \mathbf{0}\),公理 3 直接破产。

那问题来了:电子游戏里角色明明又转又平移,怎么做到"一个矩阵搞定"的?

答案是——仿射变换 (affine transformation) + 齐次坐标 (homogeneous coordinates)。

仿射变换定义为:

\[\mathbf{y} = A\mathbf{x} + \mathbf{t}\]

它是"线性变换 + 平移"的组合。仿射保直线、保平行,但不保距离和角度。

trick 在这里:为了把 \(A\mathbf{x} + \mathbf{t}\) 写成一次矩阵乘法,我们给每个向量后面补一个 1:

\[\begin{bmatrix} A & \mathbf{t} \\ \mathbf{0}^\top & 1 \end{bmatrix} \begin{bmatrix} \mathbf{x} \\ 1 \end{bmatrix} = \begin{bmatrix} A\mathbf{x} + \mathbf{t} \\ 1 \end{bmatrix}\]

\(n\) 维空间的仿射变换就升到 \((n+1) \times (n+1)\) 的矩阵。这样"平移"也被塞进矩阵乘法框架里了。

数字例。在 \(\mathbb{R}^2\) 里,"旋转 90 度再平移 \((3, 0)\)"合起来就是

\[M = \begin{bmatrix} 0 & -1 & 3 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{bmatrix}\]

用它去乘 \((1, 0, 1)^\top\):得到 \((0 + 0 + 3,\ 1 + 0 + 0,\ 1)^\top = (3, 1, 1)^\top\)。前两位是 \((3, 1)\)——原点先转 90 度还在原点(因为旋转不动原点),再平移到 \((3, 0)\)……等等,我说错了,我们送的是 \((1, 0)\)。\((1, 0)\) 旋转 90 度到 \((0, 1)\),再平移 \((3, 0)\) 到 \((3, 1)\)。对上了。

⏸️ 暂停思考 · 第二次

OpenGL 里,一个 3D 顶点的坐标写成 \((x, y, z, 1)\)——四个数。为什么末尾多一个 1? 想想我们刚刚干的事情。

(答案:因为要让 3D 空间里的平移也能用一次矩阵乘法表示。补 1 就是齐次坐标的 trick,让 \(4 \times 4\) 矩阵同时装下旋转、缩放和平移。整个计算机图形学的坐标变换管线,靠的就是这个。)


核心概念五 · 换基后同一个变换长什么样(约 3 分钟)

到这一步,你已经会用矩阵刻画变换、会算复合变换、会区分线性和仿射。但还有最后一件事:同一个变换,在不同基下写出来的矩阵不一样。

回想 Ch01 §05 那条口诀——

"\(P\) 的列是新基,\(P\) 把新坐标搬回旧描述。"

设有个线性变换 \(T\)。在标准基下,它的矩阵是 \(A\);在新基 \(\{\mathbf{b}_1, \mathbf{b}_2\}\) 下,它的矩阵是 \(\tilde A\)。它俩什么关系?

相似变换公式(记牢,Ch02 后面对角化整节都靠它):

\[\tilde A = P^{-1} A P\]

新 = \(P^{-1}\) · 旧 · \(P\)。别写反,写反了后面特征值全崩。

怎么理解?直观上:拿一个"用新坐标写的向量",先用 \(P\) 把它翻译回旧坐标(因为 \(A\) 只会读旧坐标),扔进 \(A\) 变换一下,得到旧坐标下的结果,最后用 \(P^{-1}\) 把结果翻译回新坐标。三步合起来就是 \(P^{-1} A P\)。

好,这里 Ch01 遗留了一个断层:\(P^{-1}\) 具体怎么算?我们把这个坑今天填上。

\(2 \times 2\) 的逆矩阵有闭式:若

\[M = \begin{bmatrix} a & b \\ c & d \end{bmatrix},\quad \det M = ad - bc \ne 0\]

则

\[M^{-1} = \frac{1}{ad - bc} \begin{bmatrix} d & -b \\ -c & a \end{bmatrix}\]

口诀:主对角调换,副对角变号,除以行列式。这是 \(2 \times 2\) 唯一需要背的公式。\(3 \times 3\) 及以上一般走高斯消元,我们放到 §05 讲矩阵分解时再展开。

完整数字例子(2×2 相似变换)。🟡

设标准基下的变换 $$ A = \begin{bmatrix} 2 & 0 \ 0 & 3 \end{bmatrix} $$——沿 \(x\) 拉 2 倍、沿 \(y\) 拉 3 倍。

新基 \(\mathbf{b}_1 = (1, 1)^\top\)、\(\mathbf{b}_2 = (1, -1)^\top\)。按口诀,\(P\) 的列 = 新基旧坐标:

\[P = \begin{bmatrix} 1 & 1 \\ 1 & -1 \end{bmatrix}\]

\(\det P = 1 \cdot (-1) - 1 \cdot 1 = -2\),主对角调换、副对角变号:

\[P^{-1} = \frac{1}{-2} \begin{bmatrix} -1 & -1 \\ -1 & 1 \end{bmatrix} = \frac{1}{2} \begin{bmatrix} 1 & 1 \\ 1 & -1 \end{bmatrix}\]

(这里巧了,\(P^{-1}\) 和 \(\frac{1}{2} P\) 长得一样,因为 \(P\) 是对称的正交阵除以常数。别死记这个巧合,一般矩阵不这样。)

算 \(AP\):

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

再算 \(\tilde A = P^{-1}(AP)\):

\[\tilde A = \frac{1}{2} \begin{bmatrix} 1 & 1 \\ 1 & -1 \end{bmatrix} \begin{bmatrix} 2 & 2 \\ 3 & -3 \end{bmatrix} = \frac{1}{2} \begin{bmatrix} 5 & -1 \\ -1 & 5 \end{bmatrix} = \begin{bmatrix} 2.5 & -0.5 \\ -0.5 & 2.5 \end{bmatrix}\]

看结果:\(A\) 在标准基下是对角阵,但在 \(\{\mathbf{b}_1, \mathbf{b}_2\}\) 下变成了带副对角元的矩阵。为什么?因为新基不再和 \(A\) 的拉伸轴对齐——沿 \(\mathbf{b}_1\) 方向拉一下,会同时改变 \(\mathbf{b}_1\) 和 \(\mathbf{b}_2\) 方向的分量。

这个例子你先揣着。§05 讲特征分解时,你会看到反过来的操作:选一组特别的基,让 \(\tilde A\) 变成对角阵——那就是"对角化",也是 PCA 的核心操作。

\(3 \times 3\) 及以上矩阵求逆的具体算法(高斯消元、LU 分解),我们放到 Ch03 §05 讲。这一节你先把 \(2 \times 2\) 求逆手算会。


一个走完全程的例子(约 2.5 分钟)

现在把今天所有零件串起来,跟我一起做一遍。

任务:拿向量 \(\mathbf{v} = (2, 1)\),依次施加三个变换——先旋转 90 度、再沿 \(x\) 拉 2 倍、再做因子 \(k = 1\) 的水平错切——最后落在哪?

我给你两条路,一条逐步算、一条合成矩阵一次算,你看它们结果一致。

路径 1 · 逐步算。

第一步,旋转 90 度:$$ R = \begin{bmatrix} 0 & -1 \ 1 & 0 \end{bmatrix} $$。

\[R \mathbf{v} = \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} 2 \\ 1 \end{bmatrix} = \begin{bmatrix} -1 \\ 2 \end{bmatrix}\]

第二步,沿 \(x\) 拉 2 倍:$$ S = \begin{bmatrix} 2 & 0 \ 0 & 1 \end{bmatrix} $$。

\[S (R \mathbf{v}) = \begin{bmatrix} 2 & 0 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} -1 \\ 2 \end{bmatrix} = \begin{bmatrix} -2 \\ 2 \end{bmatrix}\]

第三步,水平错切 \(k = 1\):$$ \text{Sh} = \begin{bmatrix} 1 & 1 \ 0 & 1 \end{bmatrix} $$。

\[\text{Sh} \cdot S R \mathbf{v} = \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} -2 \\ 2 \end{bmatrix} = \begin{bmatrix} 0 \\ 2 \end{bmatrix}\]

最终点:\((0, 2)\)。

路径 2 · 合成矩阵。

把三个矩阵先乘起来,\(M = \text{Sh} \cdot S \cdot R\)。注意顺序——最先作用的写在最右边,因为它先撞上向量。

先算 \(\text{Sh} \cdot S\):

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

再乘 \(R\):

\[M = \begin{bmatrix} 2 & 1 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix} = \begin{bmatrix} 1 & -2 \\ 1 & 0 \end{bmatrix}\]

对 \(\mathbf{v} = (2, 1)\) 施加 \(M\):

\[M \mathbf{v} = \begin{bmatrix} 1 & -2 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} 2 \\ 1 \end{bmatrix} = \begin{bmatrix} 2 - 2 \\ 2 \end{bmatrix} = \begin{bmatrix} 0 \\ 2 \end{bmatrix}\]

对上了。

这个例子想让你记住三件事:

  1. 复合变换 = 矩阵乘积,顺序不能换(\(AB \ne BA\))。
  2. "最先作用的矩阵写最右边"——因为向量从右边被推进去。
  3. 你可以逐步算(省脑子),也可以先合并成一个矩阵再一次算(省时间,尤其在 GPU 上批量处理时)。

易错点回头看(约 1 分钟)

有三个坑,学生反复掉。

坑一 · 很多人以为"矩阵的每一行是新基",其实是"每一列是基向量的落点"。看到 $$ \begin{bmatrix} 2 & 1 \ 1 & 2 \end{bmatrix} $$,第一列 \((2, 1)\) 才是 \(\hat{\mathbf{i}}\) 去的地方。搞反的话,\(AB\) 和 \(BA\) 就分不清了。原因:我们用列向量做默认,\(A \mathbf{v}\) 是"左行乘右列",\(\hat{\mathbf{i}} = (1, 0)^\top\) 挑出的正是第一列。

坑二 · 很多人以为"先旋转再缩放 = 先缩放再旋转",其实一般不相等。原因:矩阵乘法不满足交换律,\(SR \ne RS\)。游戏引擎里"先转身再前进"和"先前进再转身"角色落在不同位置,就是这个道理。

坑三 · 很多人以为"平移是线性变换",其实不是。原因:平移把原点挪走,破坏了 \(T(\mathbf{0}) = \mathbf{0}\)。要用矩阵表达平移,必须升到仿射 + 齐次坐标,多补一维、多补一个 1。


与下节的钩子

到这里,你已经知道每个矩阵都能读成一次变换,也会算复合变换、会算相似变换。

但你有没有觉得——一个复杂矩阵,看它数字表根本看不出它到底在干嘛?$$ \begin{bmatrix} 2.5 & -0.5 \ -0.5 & 2.5 \end{bmatrix} $$ 你光看数字,能想到它其实就是一次伪装成"沿新基拉伸"的对角阵吗?

下一节 §05,我们回答一个问题:能不能把任意矩阵,拆成几个我们已经认识的简单变换的乘积? 比如"旋转 × 缩放 × 旋转",或者"下三角 × 上三角"。

那就是矩阵分解——SVD、LU、QR、特征分解,全都是把复杂矩阵拆成简单积木。而 PCA、最小二乘、注意力机制,全都建立在这些分解之上。

下一节见。