简介:线性代数是机器学习的底层语言,矩阵分解、特征值与奇异值等概念并非抽象理论,而是数据建模与算法设计的核心工具。其中奇异值分解(SVD)能够将任意数据矩阵拆解为模式与强度的组合,广泛应用于图像压缩、推荐系统、降维与去噪;最小二乘则通过伪逆求解过定方程组,是线性回归与模型拟合的本质。理解这些数学原理,再辅以NumPy等工程工具的代码实践,就能从矩阵视角看清学习算法的运行机制。Gilbert Strang的《Linear Algebra and Learning from Data》正是这样一本将线性代数与数据科学深度融合的英文教材,它重新编排了传统知识点,让读者在真实场景中掌握SVD、最小二乘与PCA的落地方法,为深入机器学习打下坚实基础。
1. 为什么说这本英文书是数据时代的线性代数
做机器学习的人迟早会遇到一本绕不开的英文书:Gilbert Strang 的Linear Algebra and Learning from Data。市面上讲线性代数的书很多,但大多数是给数学系写的,矩阵分解、特征值、向量空间讲得很严谨,唯独不谈“数据从哪里来,模型怎么靠矩阵算出来”。这本书的定位完全不同,它把所有线性代数概念都挂到了数据分析、深度学习、图像压缩、推荐系统这类真实任务上。换句话说,它不是让你学第二遍线代,而是让你把线代变成理解机器学习内部机制的第一语言。它的英文原版值得读,不只是因为术语原汁原味,更因为作者的叙述方式——大量用文字解释为什么这么做,而不是直接扔公式。适合两类人:一类是已经学完线代但面对机器学习公式仍然发懵的开发者,另一类是工作中需要和矩阵运算打交道、想补上数学短板的工程师。篇幅不小,但不需要一次啃完,找到了正确的阅读路径,它就能成为案头常翻的一本工具书。
90% 的人翻开这本英文书的第一反应是:和国内常用的线代教材完全不是一回事。第一章没讲行列式,而是直接用数据集讲线性代数的四个基本子空间的几何意义;第二章没去证明特征值存在性,而是拿图像处理举例,说明为什么奇异值分解比特征值分解更适合处理长方形矩阵。这种编排意味着你不能用老方法去读——抱着“看定理、抄练习、对答案”的思路读这本书,很容易翻到三分之二处就放弃。
2. 与经典教材的本质差异:从矩阵理论转向数据驱动
2.1 这本书重新编排了哪些传统知识点
传统线性代数教材的核心线索是“从行列式到特征值再到对角化”,学习路径是由理论难题驱动的;而 Strang 这本不同,它的线索是“从数据到矩阵再到学习算法”。举个例子,传统教材里最小二乘法放在最后几章,作为线性代数的应用之一;而在书里,最小二乘出现在比较靠前的位置,因为几乎所有机器学习模型的损失函数最终都落到一个最小二乘问题上。它不讲“解方程”,讲的是“用数据拟合一条线”,角度完全不同。
再看四个基本子空间。传统教材把列空间、零空间、行空间、左零空间当作抽象概念,靠画图理解;书里则用它们回答一个数据问题:一个矩阵的秩不够时,真正丢失的信息落在哪个子空间里?这一点在做数据降维和噪声滤波时非常有用。理解了行空间和零空间的关系,就能想明白主成分分析里为什么前若干个奇异向量就能近似表示整个数据集。
英文原版的另一个重要特点是引入了“学习”这个视角。书里反复出现的一个词是“learning from data”,它把线性代数的每个工具都当作一个从数据中提取规律的算子:矩阵乘法代表加权组合,伪逆代表对欠定方程组的最小能量解,SVD 代表对矩阵拉伸和旋转的拆解。学到后面你会发现,卷积神经网络的前向传播不过是一连串矩阵乘法与非线性函数的复合,而这正好是这本书试图建立的心智模型。
2.2 英文版阅读的最小知识准备
直接啃英文原版最大的障碍往往不是数学,而是术语和表达方式。这里给你一个最小知识准备清单,花两周就能完成:
- 掌握高频术语的英文形式:eigenvalue(特征值)、singular value(奇异值)、null space(零空间)、column space(列空间)、rank(秩)、pseudoinverse(伪逆)、least squares(最小二乘)、orthogonal(正交)、projection(投影)
- 提前熟悉 NumPy 的基本用法:因为书里每个算法后面都配有对应的矩阵计算说明,用 Python 验证概念比手算更快
- 选择一个版本对照阅读:在国内网上能找到 Matrix Methods in Data Analysis 的配套公开课程视频,和这本书的内容顺序高度一致,先看视频再读对应章节,理解阻力会小很多
准备完成后,不建议从头背术语,而是做一个速查表,把出现频率高、容易混淆的词记录下来。比如 row-reduced echelon form(行简化阶梯形)和 reduced row-echelon form 是同一个东西,首字母缩写是 RREF,很多初学者在这里浪费了不少时间。
3. 核心数学工具:奇异值分解与最小二乘的实际落地
3.1 SVD 在数据压缩场景中的 Python 复现
书里花了不少篇幅讲奇异值分解(Singular Value Decomposition,SVD)。为什么 SVD 是这本书的灵魂工具?因为一个矩形的数据矩阵,在 SVD 下被分解成三个矩阵的乘积:左奇异向量矩阵、奇异值对角矩阵、右奇异向量矩阵。这个分解告诉我们:任何一个数据矩阵都可以拆成“模式”和“强度”的组合,而且只要保留最大的若干个奇异值,就能用很少的存储量逼近原矩阵。
下面是我在本地跑通的一个最小示例:用 SVD 对图像矩阵做压缩。这里用了标准库里的可能性很小,我用的是 numpy 和 matplotlib。
import numpy as np import matplotlib.pyplot as plt from skimage import data, color # 加载一张灰度图,并转成 float 方便运算 img = color.rgb2gray(data.astronaut()) # 这里的 U, S, Vt 就是书里讲的 SVD 三件套 U, S, Vt = np.linalg.svd(img, full_matrices=False) # 按奇异值大小保留前30个分量,其余丢弃 k = 30 img_approx = U[:, :k] @ np.diag(S[:k]) @ Vt[:k, :] # 保存压缩结果,观察视觉效果和存储量对比 plt.imsave("svd_k30.png", img_approx, cmap="gray") print(f"原始矩阵形状: {img.shape}") print(f"压缩后存储占比: {(U[:, :k].size + k + Vt[:k, :].size) / img.size:.2%}")逻辑说明:np.linalg.svd返回的左奇异向量 U 是m x m或m x k(取决于full_matrices的设置),S 是奇异值列表,Vt 是右奇异向量的转置。代码里取前 30 个分量,相当于只保留最大的 30 个奇异值对应的模式。U[:, :k] @ np.diag(S[:k]) @ Vt[:k, :]是低秩近似,其误差可以用书中讲的 Frobenius 范数来度量——也就是所有被丢弃奇异值的平方和再开根号。参数说明:k控制压缩比,k 越大图像越清晰、存储量越大;如果 k 设成矩阵的满秩,压缩结果和原图完全一致。图像压缩只是 SVD 的表层应用,同一个机制被用在推荐系统的矩阵分解、自然语言处理的潜在语义分析上。
3.2 伪逆与最小二乘的实际含义:一个普通线性回归的矩阵解法
书中关于最小二乘的讨论有一个关键概念,叫伪逆(pseudoinverse)。很多人被这个名字吓到,但它的作用非常直观:当方程个数多于未知数、且存在噪声时,等号两边严格相等几乎是不可能的,所以我们要找的是“误差平方和最小”的解。这个解被写成公式 x = A⁺b,其中 A⁺ 就是矩阵 A 的伪逆。
在 Python 中计算伪逆有两种方式:一种是用np.linalg.pinv直接算;另一种是手写 SVD 重建伪逆。后者更贴近书里的推导,先看 SVD 版本:
import numpy as np # 构造一个过定系统:8个方程,2个未知数 A = np.array([[1, 2], [2, 3], [3, 5], [4, 7], [5, 11], [6, 13], [7, 17], [8, 19]], dtype=float) b = np.array([2.1, 3.9, 5.8, 8.1, 10.9, 13.2, 16.8, 19.5]) # 手写伪逆:A+ = V @ S^{-1} @ U^T U, S, Vt = np.linalg.svd(A, full_matrices=False) # 把奇异值取倒数,小于阈值的截断为0 S_inv = np.array([1/s if s > 1e-10 else 0 for s in S]) A_pinv = Vt.T @ np.diag(S_inv) @ U.T # 最小二乘解 x_svd = A_pinv @ b # 直接调库对比 x_pinv = np.linalg.pinv(A) @ b print("手写伪逆解:", x_svd) print("库函数解:", x_pinv) # 残差平方和验证 residual = np.linalg.norm(A @ x_svd - b) ** 2 print("残差平方和:", round(residual, 4))逻辑说明:np.linalg.svd默认返回的奇异值是从大到小排的,代码先对奇异值取倒数,然后通过阈值1e-10把接近零的奇异值过滤掉,防止数值爆炸。这样一来,伪逆的本质就是在奇异值空间中,把大奇异值保留、小奇异值截断,再乘回去。参数说明:阈值1e-10不是固定的,如果你的矩阵病态严重,可以调整到1e-8或更小;对于满秩矩阵,两种写法得到的结果几乎相同。这背后的几何意义用书里的话说就是:矩阵把数据从一个空间映射到另一个空间时,沿着奇异值最大的方向传递最多的能量,最小二乘解则是把所有测量值投影到列空间里再求坐标。理解这一点,后面看岭回归、LASSO 的矩阵表达都顺了。
4. 把书中理论落成可跑的代码:从 PCA 到线性回归
4.1 用 NumPy 实现 PCA 并解释几何意义
读完整本关于线性代数与数据学习的书,第一个值得动手做的项目是用 PCA 降维。注意,PCA 不是直接对数据矩阵做 SVD 就完事,而是要先做中心化,再去计算协方差矩阵的特征分解。书中从 SVD 出发讲 PCA 的视角非常特别,它说 PCA 的基就是数据矩阵右奇异向量张成的空间;沿着第一个右奇异向量的方向,投影后方差最大。
我常用的 PCA 实现思路是:先把数据中心化(减去每列的均值),然后做 SVD,再取右奇异向量的前 k 列作为主成分方向。看代码:
import numpy as np # 模拟一个 200x10 的数据集,每一列代表一个特征 rng = np.random.default_rng(42) X = rng.normal(size=(200, 10)) # 人为制造相关性:第2列由第1列加噪声生成,第4列由第3列加噪声生成 X[:, 1] = X[:, 0] * 0.8 + rng.normal(size=200) * 0.5 X[:, 3] = X[:, 2] * -0.6 + rng.normal(size=200) * 0.4 def pca_svd(X, k): # 中心化:每列减去均值,这样协方差矩阵才是 X^T X / (n-1) X_centered = X - X.mean(axis=0) _, _, Vt = np.linalg.svd(X_centered, full_matrices=False) # 主成分方向是 Vt 的前 k 行 components = Vt[:k, :] # 投影到新空间 X_pca = X_centered @ components.T return X_pca, components X_pca, comps = pca_svd(X, 2) print("投影后形状:", X_pca.shape) print("前两个主成分方向:", comps)逻辑说明:先做中心化是因为如果不减均值,第一主成分会被变量的平均值带偏,而不是真正表示方差最大方向。np.linalg.svd返回的Vt就是右奇异向量的转置,它的前 k 行就是主成分方向。把中心化后的数据乘上components.T,就把 10 维数据降到 2 维。参数说明:k是目标维度,选择 k 的常见依据是看奇异值占比,用S[:k].sum() / S.sum()计算累计方差解释率,一般保留 80% 以上。书里特别提醒:对高维稀疏数据做 PCA 前,要考虑是否需要先做特征缩放,否则特征量纲不同会让主成分被数值大的特征主导。
4.2 对比书中解析解与梯度下降的差异
这本书的一个核心论题是:最小二乘既可以用伪逆直接求出解析解,也可以用梯度下降逐步逼近。前者适合小数据集、特征维度不太高的场景,后者适合数据量大、无法一次性装入内存的场景。这里我把两种方法放在同一份代码里做对比,并给出必要的参数说明。
import numpy as np # 生成模拟数据:10000个样本,5个特征,加上随机噪声 rng = np.random.default_rng(7) m, n = 10000, 5 X = rng.normal(size=(m, n)) true_w = np.array([1.5, -2.0, 0.8, 3.1, -1.2]) y = X @ true_w + rng.normal(size=m) * 0.3 # 解法1:正规方程 (X^T X)^{-1} X^T y,等价于伪逆 w_closed = np.linalg.inv(X.T @ X) @ X.T @ y # 解法2:批量梯度下降,固定步长0.01,迭代200轮 alpha = 0.01 iters = 200 w_gd = np.zeros(n) for i in range(iters): grad = (1/m) * X.T @ (X @ w_gd - y) w_gd = w_gd - alpha * grad print("解析解系数:", w_closed) print("梯度下降系数:", w_gd)逻辑说明:正规方程的做法是直接解X^T X w = X^T y,它的计算复杂度是 O(n^3),n 是特征数。代码里np.linalg.inv(X.T @ X)用的是求逆,实际上更好的做法是用np.linalg.solve避免数值不稳定,这里写求逆是为了语义更直白。梯度下降则每一轮都计算一次梯度X.T @ (X @ w_gd - y) / m,然后沿负梯度方向走一小步。参数说明:alpha是学习率,太大会震荡,太小收敛慢,可以按 0.01、0.001、0.1 三档调试;iters是迭代轮数,判断收敛不能只看轮数,要看损失下降曲线,通常我会把损失记录下来每 10 轮打印一次。书里提到的一个要点值得反复体会:解析解是全局最优的,但当特征数上万时求逆几乎不可行,这时梯度下降才是工程常态。
5. 避坑:读原著最常见的 5 个翻车现场
5.1 现象:只看正文不做练习,越往后越看不懂
很多人读英文教材的习惯是“通读正文,练习跳过”,这本书拖到最后几章你会发现自己完全跟不上。原因在于 Strang 的叙述方式不是“定理-证明-推论”的闭环,而是靠练习来补全很多重要的边界 case,比如欠定方程的最小范数解、列向量线性相关时 SVD 的截断行为,这些在正文里只提一句,真正理解要靠练习里的反例。
解决方法是:每章做 3~5 道题即可,尤其是带“find the projection”和“compute the SVD”的题目,不用做完所有题。这一步能节省至少一半的返工时间。
5.2 现象:用中文译本对照读,但对不上术语
英译本中译本的术语对照错误很多,比如“column space”有的版本翻译成“列空间”,有的翻译成“列张成的空间”,同一个意思两种说法,初学者往往无从判断是不是同一个概念。更麻烦的是,当视频课和习题里都使用英文术语时,中文术语反而制造认知障碍。
解决方法是:一开始就把术语表的英文当成主版本,中文只作为辅助理解。把每个术语的英文写在笔记的第一列,中文解释写在后面,这样检索时以英文为准。
5.3 现象:SVD 的前几个奇异向量被当成“最重要的特征”,直接做特征筛选
书中明确说了 SVD 提供的是一种低秩近似,不等同于“这些列本身代表了原始数据最关键的几个特征”。我曾见某开发者在做特征选择时,直接把右奇异向量的第一个分量当成特征重要性的排序,结果模型效果大幅下降。原因在于主成分方向是特征的线性组合,不是原始特征本身,用组合系数去解释单一特征的重要性会产生误导。
解决方法是:做特征筛选时用随机森林的重要性分数,或者用 Lasso 的特征稀疏化方式;SVD 只用来做降维、压缩和去噪。
5.4 现象:把特征值分解当 SVD 用,处理非方阵时直接报错
书中特别提醒 SVD 适用于任意矩阵,而特征值分解仅适用于方阵且有足够的线性无关特征向量。很多初学者在代码里写np.linalg.eig(A)处理一个 300x10 的数据矩阵,结果报错后改用np.linalg.eig(A.T @ A),这样虽然能运行,但算出来的是 A 的右奇异向量的平方根,而不是真正的奇异值分解,而且数值稳定性会比直接 SVD 差。解决方法是:任何情况下都使用np.linalg.svd,没有例外。
5.5 现象:混淆“正交”与“线性无关”
书里大量使用“orthogonal”这个词,但它不是“not linearly dependent”的同义词。正交要求内积为零,线性无关只要求不能相互线性表出。两列非正交但线性无关是完全正常的。一个常见的翻车场景是在检查 PCA 降维结果时,发现两个主成分的散点图不是 90 度直角,于是怀疑代码写错了。其实主成分方向是正交的,但投影后的散点图坐标轴是原始空间中的正交方向,图形上的角度受缩放影响,和正交性无关。
解决方法是:用数值验证而不是看图判断,直接计算components @ components.T,如果是单位矩阵,说明正交性正确。
6. 书后自测:用三个小实验确认自己真的读懂了
读完这本书,最容易出现的错觉是“我好像都会了”。我给自己设计了三个小实验作为验证,每个实验都能在半小时内完成,却能暴露理解漏洞。
第一个实验:随机生成一个 1000x10 的数据矩阵,用 SVD 降到 3 维,再重建回 10 维,计算重建误差;然后改用特征值分解法做同样的事,比较两组误差。如果你能解释为什么 SVD 重建误差更小,说明你对低秩近似的理解是对的。否则回到第 3.1 节的代码重新看。
第二个实验:在 100 个样本、20 个特征的合成数据上,分别用正规方程和梯度下降求解线性回归,然后不断把学习率提升到 0.1、0.5、1.0,观察损失曲线的变化。如果梯度下降的发散或振荡无法从矩阵条件数的角度解释,说明你还没有把矩阵分析和优化算法联系起来。
第三个实验:用书中讲的伪逆观点,给一个欠定方程组Ax=b(未知数多于方程数)找出最小范数解,再对比np.linalg.lstsq的结果。如果你能答出“最小范数解 = 零空间正交补上的投影”,那这本书的核心思想就真的落地了。
做完这三个实验,你还可以做一个更进阶的验证:用 SVD 对推荐系统中的用户-物品评分矩阵做降维补全,把补全后的评分和原始观测值做对比。这是把书中 SVD 的低秩近似想法映射到具体业务的常见做法,也是一个很好的自我检验方式。
最后,就我个人读这本书的经验来说,最大的教训是别贪快。附录里的四个矩阵子空间图值得反复看,每次看都会有新的理解。记笔记时把每个概念用一个“数据场景”来锚定,比抄定义有用得多。矩阵乘法是加权组合,特征分解是找到不变量,SVD 是找到数据的主轴,伪逆是解决噪声世界中方程矛盾的最好方式。这些叙述句,比任何公式都经得起时间考验。
希望这些路径和踩坑记录能帮到你少走一段弯路。读完这六章再回头看这本书,你会觉得它不是一本教材,而是一副看数据的眼镜。
本文还有配套的精品资源,点击获取