想象你要用三根长短不一的木条搭一个直角书架。你当然可以把它们随便钉在一起,但那样书放不稳。真正的做法是:先选定第一根木条,然后把第二根木条上“斜向第一根”的部分锯掉,只保留与第一根垂直的分量;第三根则要同时锯掉“斜向第一根”和“斜向第二根”的分量。最后把每一根按同一刻度截成单位长度。这套“锯斜留直、再定刻度”的流程,就是 Gram-Schmidt 正交化。它把一组彼此不垂直、长度不一的向量,加工成一组标准正交基——就像把歪斜的木条变成横平竖直的直角骨架。
掌握 Gram-Schmidt 是理解 QR 分解、最小二乘和信号处理的一把钥匙;对 AI 工程师而言,它是数值优化与特征计算中稳定建模的基本功。
目录
可视化演示
\u5c55\u793a\u5411\u91cf\u6b63\u4ea4\u5316\u6295\u5f71\u51cf\u9664\u3001\u6807\u51c6\u6b63\u4ea4\u57fa\u6784\u9020\u53caQR\u5206\u89e3\u7684\u77e9\u9635\u5173\u7cfb\u3002
本节配有交互动效(进入视口后自动加载,约 3KB)。
\u6b63\u4ea4\u5316\u8fc7\u7a0b v1=a1\u4f5c\u4e3a\u7b2c\u4e00\u4e2a\u6b63\u4ea4\u57fa v2=a2-proj(v2,v1) q_i = v_i / ||v_i|| \u9010\u6b65\u6784\u9020\u4e24\u4e24\u6b63\u4ea4\u7684\u5411\u91cf\u57fa
正交化思想:从斜支架到直角基
假设你刚从树林里捡回三根木条,左看右看都歪歪扭扭。直接钉在一起虽然能立住,但架子上放书时,总会顺着木条的斜向滑下去。在线性代数里,这些木条就是向量,它们共同撑起的空间叫向量空间。只要没有一根木条能被其余木条拼出来,就说这组向量线性无关。
线性无关保证了骨架不会有多余料,但没保证方向好。理想支架要求三根木条两两垂直,并且长度都按同一刻度取整。两两垂直的向量称为正交;长度为 1 的向量叫单位向量。由此得到的“两两正交且单位长度”的一组基,就是标准正交基。标准正交基下的坐标计算异常省力:想求某个向量在某个方向上的分量,直接做一次内积即可,不必解方程组。
判断垂直需要一把“内积尺”。在 n 维实数空间中,两个向量的内积就是把对应分量相乘后再全部加起来。内积为零,便说明两个方向互相垂直。
这就像直角书架中的横梁与竖梁:它们内积为零,彼此不抢方向,才能稳稳托住每一层。
- 对应分量内积的第一件事是把 u 的第 i 个分量与 v 的第 i 个分量相乘。
- 累加求和把所有乘积相加,得到反映两个向量“方向一致性”的单一数值。
- 判零即垂直如果累加结果为零,说明两个向量没有共享的方向成分。
经典GS推导:一根一根锯
现在该正式动锯了。Gram-Schmidt 的核心工具是投影:把一根向量往另一根方向上“照影子”。影子长度就是投影系数;影子的方向沿着被投影的那根向量。要得到与 u 垂直的 v 分量,只需把 v 在 u 上的影子剪掉。
给定线性无关向量 v1……vk,算法让第一根原封不动:u1=v1。到第二根,v2 减去它在 u1 上的投影,余下的 u2 自然与 u1 垂直。到第三根,v3 减去它在 u1 和 u2 上的投影,余下的 u3 同时垂直于前两个方向。一步步做下去,就得到两两正交的 u1……uk。最后把每个 u_i 除以自身长度,得到长度为 1 的标准正交向量 e_i。
原本歪斜的一捆木条,经过一把投影锯和一把刻度尺,就变成横平竖直的标准直角骨架。
- 第一步保底第一根没有参照物,直接保留原方向。
- 算投影系数每个投影系数是 v_k 在已产出 u_j 方向上的影子长度除以 u_j 的模长平方。
- 统一扣除把 k-1 个影子全部剪掉,剩余部分与所有 u_j 垂直。
- 单位化除以自身长度,得到标准正交向量。
改进MGS:边锯边量
经典 GS 的做法是:先把一根木条上“斜向所有已固定横梁”的影子全部量出来,再一次性锯掉。万一木条本身略弯,量影子时就会把前一根的误差也掺进来。改进版 MGS 则改为:对准第一根横梁锯一下,停下来看看剩余木条;再对准第二根锯一下,再看一眼。每锯一次都基于最新剩余量,误差不容易累积。
数学上,MGS 和经典 GS 完全相同——都是在扣掉前 k-1 个方向上的投影。差别只是实现顺序:经典 GS 用原始 v_k 与每个 q_j 算投影,MGS 用不断更新的 w 与 q_j 算投影。这一顺序变化在纸面上看微不足道,在浮点运算中却能决定 q_i 是否还保持正交。
MGS 是那位每次只锯一下、反复检查的工匠;虽然多做几次停顿,成品却更接近直角。
- 初始化当前木条把待加工的 v_k 复制给 w,之后的每次修改都在 w 上发生。
- 量影子长度用当前剩余 w 与已固定的 q_j 做内积,得到本次该锯掉的投影长度。
- 锯掉影子从 w 中减去 r_{jk} q_j,剩余部分开始与 q_j 垂直。
- 归一化收尾把所有影子都锯完后,除以剩余长度,得到第 k 个标准正交向量。
QR分解联系:木条的登记簿
正交化不只是把木条摆正,它还会留下账本:每根原始木条到底由多少根标准横梁拼接而成。把这些拼接系数按顺序写成一个矩阵,就可以把整套操作浓缩成一条矩阵等式——QR 分解。
设 A 的列是原始向量 v1……vn,Q 的列是标准正交向量 q1……qn,R 是上三角矩阵,则 A=QR。因为 Q 的列标准正交,Q^T Q=I;R 的上三角性来自每个 v_k 只由前 k 个 q_i 表示。求解 Ax=b 时,先两边左乘 Q^T 得 Rx=Q^T b,再用从最后一行往前的回代求出 x。
账本一旦写好,以后任何右端项 b 都能快速结算;这正是 QR 分解在最小二乘中如此值钱的原因。
- 构造 Q 列Q 的每一列就是正交化并单位化后的 q_i,列与列之间标准正交。
- 记录 R 系数R 的第 i 行第 k 列记录 q_i 在 v_k 中的贡献,i>k 时系数为 0,因此是上三角。
- 还原关系每个 v_k 都能写成前 k 个 q_i 的线性组合。
- 回代求解方程 Ax=b 变为 Rx=Q^T b,从最后一行往上逐行解出 x。
数值稳定性:浮点世界的“差不多”
现实世界的木条都有粗细、弯曲,计算机里的数字也有“舍入误差”。浮点数只能近似表示小数,每次加减乘除都会在最后一位产生小偏差。如果两根木条几乎顺着同一方向,“减去投影”就会变成两个非常接近的大数相减,真正代表垂直分量的信息藏在末尾几个小数位上,很容易被舍入误差吞掉。
条件数 κ(A) 刻画了这捆木条有多“接近倒塌”。条件数越大,微小扰动越可能被放大。经典 GS 一次性扣除所有影子,在病态矩阵上容易让 q_i 失去正交性;MGS 逐次更新剩余量,把每一步的舍入影响控制在更小的范围。若仍不够,可以再做一次正交化(reorthogonalization),相当于把已经摆正的支架再校准一遍。
算法步骤一模一样,只因“先锯后量”还是“边锯边量”,最终成品的直角精度可能天差地别。
- 机器精度ε_mach 是浮点系统中能区分相邻数字的最小间隔,约 2^-52。
- 条件数κ(A) 是矩阵“病态程度”的度量,接近线性相关时它会非常大。
- 正交性误差左边衡量计算出的 Q 有多偏离单位正交矩阵;误差上界被条件数和机器精度联合放大。
应用实例:多项式与信号空间的直角骨架
把函数也看作向量,Gram-Schmidt 就能从普通空间走进函数空间。比如定义在 [-1,1] 上的函数 f(x),g(x),它们的内积是乘积的积分;若这个积分为零,就称它们在函数空间里垂直。函数空间没有直观的箭头,但有同样的直角规则。
对函数组 1,x,x^2 依次做 Gram-Schmidt,会得到经典的正交多项式族:常数 1、一次项 x、二次项 x^2-1/3,继续做下去就是 Legendre 多项式。它们能把复杂函数拆成正交成分,是数值积分和谱方法的基石。信号处理中,连续信号同样可以看成向量空间中一个点,Gram-Schmidt 可为信号构造正交基底,用于压缩、去噪和特征提取。
木条变成了函数曲线,直角支架变成了正交函数系;同一个算法,在不同的“空间”继续盖房子。
\langle f,g\rangle=\int_{-1}^{1} f(x)g(x)\,dx,\qquadp_0(x)=1,\quad p_1(x)=x,\quad p_2(x)=x^2-\frac{\langle x^2,1\rangle}{\langle 1,1\rangle}\cdot 1-\frac{\langle x^2,x\rangle}{\langle x,x\rangle}\cdot x=x^2-\frac{1}{3}.- 定义内积函数的内积是两个函数相乘后在整个区间上积分,它是几何内积的连续版本。
- 常数项扣除x^2 与常数 1 的投影系数是 ∫x^2 dx 除以 ∫1 dx。
- 一次项扣除x^2 与 x 的内积是 ∫x^3 dx=0,所以一次项系数为 0。
- 得到正交多项式p_2(x)=x^2-1/3,它与 p_0(x)=1 和 p_1(x)=x 都正交。
实现与思考:工程中的选择
现在回到工程视角。实现 Gram-Schmidt 时,最直观的写法是:对每一列 v_k,先让 w=v_k,再依次对 j=1..k-1 计算它在 q_j 上的投影并扣掉,最后归一化得到 q_k。这个流程简单、可增量、适合在线处理,计算量也相当可控。
设矩阵 A 有 m 行 n 列,Gram-Schmidt QR 约需 2mn^2 次浮点运算。这个复杂度与 Householder QR 同阶,所以在大规模稠密矩阵上并没有绝对优势;通用数值库更多使用 Householder 或 Givens 变换。MGS 的真正舞台是迭代算法、最小二乘修正和信号处理这类需要逐步构建、更新正交基的场景。
就像盖房时既可以用预制件,也可以现场支模;Gram-Schmidt 是理解整套正交化技术族的地基,知道何时用它,才能在建好的房子里不迷路。
- 列循环算法对每一列都做一次完整的“锯影子”处理。
- 单次内积成本每一列要与前面 k-1 个已固定方向做内积,每个内积需要 m 次乘法。
- 累加求和所有列的投影工作合计约 mn^2/2 次乘法,归一化与减法再各贡献一部分。
- 总复杂度综合投影、减法和归一化后,总计算量约 2mn^2。
AI 应用场景
场景一:线性回归的稳定最小二乘
阶段:特征建模与数值优化
解决的问题:传统方式直接解正规方程 X^T X β = X^T y,会把矩阵条件数平方;当特征高度相关时,结果对微小噪声极敏感。用 Gram-Schmidt 完成设计矩阵的 QR 分解后,问题变成解 R β = Q^T y,避免平方条件数,数值更稳。
具体案例:某电商公司预测商品销量,特征包含价格、促销时长、点击量等高度相关字段。工程师对设计矩阵做 QR 分解,把原始特征空间换成标准正交方向,再计算回归系数;即使特征强相关,模型系数也不再剧烈震荡。
场景二:信号空间的正交基构造
阶段:信号预处理与特征提取
解决的问题:传感器采集的原始信号通常包含大量冗余成分。直接使用原始波形作为特征,会让分类器关注到重复信息;Gram-Schmidt 能在候选波形上构造正交基底,让投影系数相互独立。
具体案例:可穿戴设备采集心电与加速度信号,算法工程师把典型心跳波形视为向量,用 Gram-Schmidt 生成一组正交基,再对每段信号做投影,得到低维且去相关的心拍特征,用于心律不齐分类。
Python 演示
import math def modified_gram_schmidt(A): # input: A is a list of column vectors # output: Q, R such that A = Q * R n = len(A) m = len(A[0]) Q = [] R = [[0.0] * n for _ in range(n)] for k in range(n): w = A[k][:] for j in range(k): R[j][k] = sum(Q[j][i] * w[i] for i in range(m)) w = [w[i] - R[j][k] * Q[j][i] for i in range(m)] R[k][k] = math.sqrt(sum(x * x for x in w)) Q.append([x / R[k][k] for x in w]) return Q, R def orthogonality_error(Q): n = len(Q) m = len(Q[0]) err = 0.0 for i in range(n): for j in range(n): s = sum(Q[i][t] * Q[j][t] for t in range(m)) if i == j: s -= 1.0 err = max(err, abs(s)) return err if __name__ == "__main__": A = [[1.0, 2.0, 2.0], [2.0, 1.0, 0.0]] Q, R = modified_gram_schmidt(A) print("Q =", Q) print("R =", R) print("orthogonality error =", orthogonality_error(Q))
w = A[k][:]把第 k 列复制为“当前剩余木条”,后续修改都在这份副本上发生。R[j][k] = sum(Q[j][i] * w[i] for i in range(m))计算当前剩余向量在 q_j 方向上的投影长度。w = [w[i] - R[j][k] * Q[j][i] for i in range(m)]每知道一个投影,就立刻把它从剩余向量中锯掉。R[k][k] = math.sqrt(sum(x * x for x in w))锯完所有影子后,剩余长度就是 R 的对角元。Q.append([x / R[k][k] for x in w])归一化后,把第 k 个标准正交向量放回 Q。
常见误区
误区初学者会以为正交化只是三维空间里把向量画成箭头、量角器画垂直,跟函数和信号没关系。
正解Gram-Schmidt 只需要一个满足线性性的内积。函数、多项式、信号都可以定义内积,算法完全一样;它不是在画图,而是在任意内积空间里搭直角骨架。
为何常见:教材总用二维、三维向量图引入,投影图太有画面感,导致把“空间”想象成几何空间。
误区看到 MGS 的伪代码和经典 GS 不一样,就以为它们不是同一个算法。
正解在精确实数运算中,MGS 和经典 GS 完全等价,都是依次扣除前 k-1 个方向上的投影;只是计算顺序不同,浮点舍入误差的累积方式也因此不同。
为何常见:算法课强调步骤,数值分析讲误差,初学者把“实现细节”误当成“数学内容”。
误区只要输入的向量线性无关,经典 GS 一定能在计算机上得到一组近乎完美的正交基。
正解线性无关是精确数学条件;浮点计算中,若向量接近线性相关,减去投影时会发生灾难性抵消。此时应选用 MGS、Householder 或重正交化。
为何常见:离散数学与数值计算脱节:课堂用实数推导,而计算机只能用有限精度小数。
误区学会 GS 后,以为所有库中的 qr 函数都内部调用 Gram-Schmidt。
正解GS 只是构造 QR 的一种途径。LAPACK 等成熟库通常用 Householder 变换或 Givens 旋转,因为数值性质更好;但 GS 能直观解释 QR 的结构。
为何常见:教材从 GS 引出 QR,学习者把教学顺序当成了实现顺序。
面试题
Q1. Gram-Schmidt 正交化的目标是?
- A.把正交基变成线性相关
- B.把线性无关向量化成正交向量← 正确答案
- C.把任意矩阵变成对角阵
- D.把特征值全部变成零
答案:B。Gram-Schmidt 的输入是线性无关向量组,输出是两两正交且可单位化的向量组,就像把一捆斜木条收拾成直角骨架。A 理解反了,C 属于对角化,D 属于特征值话题。
Q2. 在标准欧氏空间中,判定两个向量正交的条件是?
- A.两个向量内积为零← 正确答案
- B.两个向量模长相等
- C.两个向量方向相反
- D.两个向量长度为一
答案:A。内积为零说明两个向量没有共享的方向成分,好比横梁和竖梁互不占对方的方向。模长相等、方向相反或长度为一都与垂直无关。
Q3. 经典 GS 处理第二个向量时,第一步要做什么?
- A.先把矩阵转置一下
- B.减去前一个方向上的投影← 正确答案
- C.直接对每个向量取模
- D.把所有向量取平均
答案:B。第二个向量要先减去它在第一个方向上的投影,剩下的部分才与第一个方向垂直。转置、取模和平均都不是正交化步骤。
Q4. 关于经典 GS 与 MGS,下列说法正确的是?
- A.数学上完全等价← 正确答案
- B.MGS 通常更抗舍入误差← 正确答案
- C.经典 GS 总是更稳定
- D.两者的数学结果不同
答案:AB。在精确实数运算中两者数学等价,只是计算顺序不同;MGS 边扣边更新,通常更抗舍入误差。C 说反了,D 与等价性矛盾。
Q5. QR 分解中的矩阵 Q 满足?
- A.列向量标准正交← 正确答案
- B.行向量全为负数
- C.所有元素都是整数
- D.矩阵必然可逆
答案:A。Q 的列来自 Gram-Schmidt 的输出,因此两两正交且长度为 1。Q 不一定是方阵,所以“必然可逆”并不准确,元素也未必是整数。
Q6. 用 QR 分解求解 Ax=b,接下来的核心运算是?
- A.解 Rx=Q^T b← 正确答案
- B.解 Qx=R^T b
- C.用高斯消去 A
- D.把 x 设为 Qb
答案:A。Ax=b 且 A=QR,则 QRx=b;左乘 Q^T 后得到 Rx=Q^T b,再回代求解。其他选项都颠倒了 Q 和 R 的角色。
Q7. 标准 QR 分解要求矩阵 A 的列?
- A.A 的列线性无关← 正确答案
- B.A 的列两两正交
- C.A 的列单位长度
- D.A 的列全不为零
答案:A。Gram-Schmidt 的前提是列向量线性无关;若输入列已经正交或单位化,就不需要“分解”了,全不为零也不足以保证线性无关。
Q8. Gram-Schmidt 的典型应用包括?
- A.构造多项式正交基← 正确答案
- B.构造信号空间基底← 正确答案
- C.直接求出所有特征值
- D.完成矩阵的 QR 分解← 正确答案
答案:ABD。Gram-Schmidt 可用于多项式正交化、信号空间基底构造和 QR 分解。它本身不计算特征值,那是特征值算法的任务。
Q9. 当 MGS 之后 Q 仍不够正交时,常用补救手段是?
- A.再做一次重正交化← 正确答案
- B.把向量长度加长
- C.去掉维度最大的向量
- D.改用随机初始化
答案:A。重正交化是把已得到的 q 向量再执行一遍正交化流程,相当于把支架重新校准一次。加长、删维度、随机初始化都无法恢复正交性。
Q10. 接近线性相关时,经典 GS 最主要的舍入误差来源是?
- A.两个相近数相减的消去← 正确答案
- B.两个相近数相加溢出
- C.除法运算次数过多
- D.转置过程引入误差
答案:A。当两列几乎同向,投影系数接近 1,v_k 减投影时是“两个相近大数相减”,真正的小分量被舍入误差吞掉。转置不产生误差,除法次数不是主要问题。