基与对偶¶
一句话总结:基是给向量空间搭坐标系的最小骨架,对偶基则是配套的一组"尺子"; \(P\) 与 \(P^{-1}\) 让两组基彼此翻译,撑起 PCA 与注意力等机器学习变换。
基定义了向量空间的坐标系,对偶则揭示线性函数如何作用于向量。本文覆盖线性无关、张成集、基变换、对偶空间和余向量 (covector) —— 这些概念是机器学习中主成分分析 (Principal Component Analysis, PCA)、特征变换和注意力查询背后的骨架。
-
我们已经看到,向量活在具有一定维数的空间里。但究竟是什么定义了这些维数?这就是基向量 (basis vectors) 登场的地方。
-
基 (basis) 是一组向量,通过缩放和相加 (线性组合) 就能搭出空间里的每一个向量,而且没有冗余。它们是空间的构造积木。
-
一组基必须满足两个条件:
-
线性无关 (Linearly independent):任何一个基向量都不能由其他基向量搭出来。每一个都贡献一个真正新的方向。
-
张成 (Spanning):空间里的每一个向量都能表示为基向量的组合。一个不漏。
-
-
一组基里向量的数量等于空间的维度 (dimension)。在 \(\mathbb{R}^2\) 里你需要 2 个,在 \(\mathbb{R}^3\) 里你需要 3 个,依此类推。
-
最自然的基是标准基 (standard basis),也就是沿每条坐标轴的单位向量:
- 在 \(\mathbb{R}^2\) 里:\(\hat{\mathbf{i}} = (1, 0)\) 和 \(\hat{\mathbf{j}} = (0, 1)\)
- 在 \(\mathbb{R}^3\) 里:\(\hat{\mathbf{i}} = (1, 0, 0)\)、\(\hat{\mathbf{j}} = (0, 1, 0)\)、\(\hat{\mathbf{k}} = (0, 0, 1)\)
-
任何向量都不过是这些基向量的加权和。向量 \((3, 2)\) 其实就是 \(3\hat{\mathbf{i}} + 2\hat{\mathbf{j}}\)。权重 (3 和 2) 就是这个向量在该基下的坐标 (coordinates)。
-
但标准基并不是唯一有效的基。在 \(\mathbb{R}^2\) 里,向量 \((1, 1)\) 和 \((-1, 1)\) 也构成一组基。它们线性无关,能够触达平面上的任意一点。同一个向量在这组新基下会有不同的坐标,仅此而已。
-
基变换 (change of basis) 就是用不同的基重新表达同一个向量。向量并没有动,我们只是从另一个视角来描述它。
-
具体做法是乘以一个基变换矩阵 (change of basis matrix) \(P\),\(P\) 的列就是用旧坐标写出来的新基向量。要变回去,就乘以 \(P^{-1}\)。
-
把它想象成两位朋友给同一家咖啡馆指路。你按街道走:\((3, 2)\) 意思是"往东 3 个街区,往北 2 个街区"。你的朋友按对角线走:她的方向是 \(\mathbf{b}_1 = (1, 1)\) (东北) 和 \(\mathbf{b}_2 = (-1, 1)\) (西北),也就是刚才那组新基。同一家咖啡馆,两套描述如何抵达的语言。
-
你朋友说咖啡馆在 \((2.5, -0.5)\):""沿我的东北对角线走 2.5 步,然后沿我的西北对角线倒着走半步"。要知道这句话翻成你的街道语言是什么,你只要照着她的配方来一遍:
-
这就是你叫做 \((3, 2)\) 的同一家咖啡馆!
-
"照配方走一遍"这个动作恰恰就是乘以 \(P\) 做的事。把朋友的基向量按列堆叠起来,再乘一个装着她坐标的向量,就是把第一列取 2.5 份、第二列取 -0.5 份,还是那个配方,只不过写得更紧凑:
- 反过来翻译,把你的 \((3, 2)\) 翻成朋友的语言,就意味着把配方倒回去,而把 \(P\) 倒回去正是 \(P^{-1}\) 干的活:
-
什么都没动。\((3, 2)\) 和 \((2.5, -0.5)\) 是同一个点的两种描述,\(P\) 就是在这两种描述之间做翻译的字典。
-
在机器学习里,基变换频繁出现。例如 PCA 会找到一组新基 (主成分),让数据更容易理解——坐标轴会对齐到方差最大的方向。
-
接下来这组概念会比较抽象,现在乍看不太好抓住,要等到后面章节里我们真的用上它们才会变得直观,所以扶稳了,抱歉。
-
好,这里其实藏着一个更深的想法。当我们写 \(\mathbf{v} = (3, 2)\) 时,坐标 3 和 2 其实是"沿每个基方向去测量" \(\mathbf{v}\) 的结果。第一个坐标在问"\(\mathbf{v}\) 里有多少 \(\hat{\mathbf{i}}\)?",第二个在问"有多少 \(\hat{\mathbf{j}}\)?"
-
在咖啡馆的故事里,这些测量就是朋友的两个问题:"你沿我的东北对角线走了多远?"和"沿我的西北对角线走了多远?"每一组基都自带一组问题,每个方向一个。
-
每一个问题都是一个线性泛函 (linear functional):接收一个向量、返回一个数字 (读数) 的函数。
-
线性这个词是说,这个泛函尊重向量空间的两种运算。测量两个向量之和,得到的是各自读数之和;把一个向量翻倍,读数也翻倍:
-
换句话说,线性泛函是诚实的尺子。向量是被测量的对象,线性泛函是测量它们的尺子,而所有可能尺子的集合就构成了对偶空间 (dual space) \(V^\ast\)。
-
对每一组基 \(\{\mathbf{e}_1, \mathbf{e}_2, \ldots, \mathbf{e}_n\}\),都有一套配套的尺子——对偶基 (dual basis) \(\{\mathbf{e}_1^\ast, \mathbf{e}_2^\ast, \ldots, \mathbf{e}_n^\ast\}\),其中 \(\mathbf{e}_i^\ast\) 只回答一个问题:"有多少步 \(\mathbf{e}_i\)?"。一把校准良好的尺子在它对应的那个基向量上读数为 1,对其他所有基向量彻底无视——这一点可以用克罗内克 δ (Kronecker delta) \(\delta_{ij}\) 紧凑地写出来:
- 一把尺子只需要这么一条小小的校准规则就够了,因为线性会帮它把剩下的事做完。看看 \(\mathbf{e}_1^\ast\) 读取 \(\mathbf{v} = 3\mathbf{e}_1 + 2\mathbf{e}_2\) 的第一个坐标:
-
这把尺子无视所有除它自己以外的方向,只报告一个坐标。坐标就是对偶基读数。
-
那么一把尺子具体长什么样?在 \(\mathbb{R}^n\) 里,每个线性泛函都不过是"一行数字,用点积作用上去"。而对于朋友那组基,其实我们已经不知不觉造出了它的尺子:把 \((3, 2)\) 翻译成朋友的语言就是乘 \(P^{-1}\),\(P^{-1}\) 的每一行产出一个坐标。\(P^{-1}\) 的行就是对偶基:
-
拿咖啡馆之行来验证一下:\(\mathbf{b}_1^\ast \cdot (3, 2) = 0.5 \cdot 3 + 0.5 \cdot 2 = 2.5\),正好就是朋友的第一个坐标。本文的两半合起来其实是同一件事:基变换换掉了构造积木,而对偶基是配套的一组尺子,用来读出新坐标。
-
校准规则也一直大大方方地躺在那儿:\(P^{-1}P = I\) 说的正是尺子 \(i\) 在基向量 \(i\) 上读 1,在其他基向量上读 0。单位矩阵不过是把克罗内克 δ 写成表格的样子。
-
一点告诫。人很容易猜想 \(\mathbf{b}_1\) 对应的尺子就是 \(\mathbf{b}_1\) 自己,也就是直接和 \((1, 1)\) 做点积。但 \((1, 1) \cdot (3, 2) = 5\),是真正坐标 2.5 的两倍。用基向量自己做点积能读出对应坐标,只在基是单位正交 (orthonormal) (互相垂直、每个长度为 1) 的时候成立,比如标准基。这就是为什么 \(\mathbf{e}_1^\ast\) 恰好长得和 \(\mathbf{e}_1\) 一模一样。对其他任何基,尺子都躲在 \(P^{-1}\) 的行里。
-
这也解释了点积的双重身份。每一个向量 \(\mathbf{u}\) 都悄悄定义了一把尺子 (用 \(\mathbf{u} \cdot \mathbf{v}\) 去测量 \(\mathbf{v}\)),而每一把尺子也不过是和某个向量做点积。在有限维里,对偶空间本质上是原空间的镜像。
-
对偶现在也许显得抽象,但它其实撑起了许多实用的想法:坐标是对偶基的求值、点积是对偶配对,而神经网络里的注意力这类变换,本质上是让一组向量"查询"另一组,这就是对偶在运作。
编程练习 (使用 CoLab 或 notebook)¶
-
用两组不同的基表达同一个向量,并验证它们代表同一个点。试着自己造一组基,看看向量在其中的坐标是什么。
import jax.numpy as jnp v = jnp.array([3.0, 2.0]) # 标准基:坐标就是分量本身 print(f"Standard basis coords: {v}") # 新基:(1,1) 和 (-1,1) P = jnp.array([[1.0, -1.0], [1.0, 1.0]]) new_coords = jnp.linalg.solve(P, v) print(f"New basis coords: {new_coords}") # 验证:用新坐标重构 reconstructed = new_coords[0] * P[:, 0] + new_coords[1] * P[:, 1] print(f"Reconstructed: {reconstructed}") -
为练习 1 中朋友的基构造对偶基 (P⁻¹ 的行),并验证每一把尺子恰好读出一个坐标。然后看看为什么用基向量自身做点积只对单位正交基才成立。
import jax.numpy as jnp v = jnp.array([3.0, 2.0]) # 朋友的基 (1,1) 和 (-1,1),按列堆叠 P = jnp.array([[1.0, -1.0], [1.0, 1.0]]) # 对偶基:P^{-1} 的行 P_inv = jnp.linalg.inv(P) b1_star, b2_star = P_inv[0], P_inv[1] print(f"b1* = {b1_star}, b2* = {b2_star}") # 每把尺子读出朋友基下的一个坐标 (与练习 1 一致!) print(f"b1*(v) = {jnp.dot(b1_star, v)}") # 2.5 print(f"b2*(v) = {jnp.dot(b2_star, v)}") # -0.5 # 校准:在自己的基向量上为 1,在另一个上为 0 print(f"b1*(b1) = {jnp.dot(b1_star, P[:, 0])}, b1*(b2) = {jnp.dot(b1_star, P[:, 1])}") # 陷阱:直接和 b1 做点积得不到坐标 print(f"b1 . v = {jnp.dot(P[:, 0], v)} (5.0, not 2.5 -- b1 is not orthonormal)") # 标准基是单位正交的,所以那里这种捷径成立 e1 = jnp.array([1.0, 0.0]) print(f"e1 . v = {jnp.dot(e1, v)} (3.0, the first standard coordinate)")
📌 本节要点¶
- 基 (basis):一组线性无关且能张成整个空间的向量,数量等于空间的维度。
- 坐标与基变换:同一向量在不同基下有不同坐标,换基矩阵 \(P\) 的列是新基向量,\(P^{-1}\) 负责反向翻译。
- 线性泛函:从向量到实数的线性函数,满足加法与数乘保持不变,是测量向量的"诚实尺子".
- 对偶空间 \(V^\ast\):所有线性泛函组成的空间,是原空间在有限维下的镜像。
- 对偶基与 Kronecker δ:对偶基 \(\{\mathbf{e}_i^\ast\}\) 由 \(\mathbf{e}_i^\ast(\mathbf{e}_j) = \delta_{ij}\) 校准,恰好读出对应坐标。
- \(P^{-1}\) 的行就是对偶基:换基矩阵的逆的每一行就是新基对应的尺子,单位矩阵 \(P^{-1}P = I\) 正是 Kronecker δ 的表格化。
- 正交陷阱:用基向量自身做点积读坐标只在单位正交基下成立,否则必须用 \(P^{-1}\) 的行。