
简介《线性代数的艺术》中文版PDF是一份面向线性代数初学者与进阶读者的图形化学习资料作者Kenji Hiranabe在Gilbert Strang《线性代数为所有人》理论基础上用可视化方式讲解矩阵运算与分解。资源包内共1个PDF文件大小约1.43MB内容涵盖理解矩阵的四个视角、向量乘向量、矩阵乘向量、矩阵乘矩阵的多种解读以及CR、LU、QR、QΛQT和奇异值分解五种矩阵分解方法并配有大量彩色示意图辅助理解。目前已有573人学习浏览。读者可借此直观把握矩阵乘法作为线性组合与秩1矩阵的本质理解各分解方法在求解线性方程组、数值计算、降维与数据压缩中的用途适合作为课堂之外的图解笔记帮助建立几何直觉、巩固理论框架。1. 从一份线性代数可视化笔记说起为什么矩阵乘法总让人卡住很多人第一次学线性代数卡住的地方不是行列式怎么算而是矩阵乘法为什么这么定义。教科书给出一行乘一列的公式然后让你做一百道计算题但很少有人告诉你矩阵乘法本质上是线性变换的复合是空间先被拉伸再被旋转的过程。有一份流传较广的开源可视化笔记用图解的方式把向量、矩阵、特征值、奇异值分解这些概念画成了几何动画中文翻译版本以 PDF 形式在社区里传播文件名就叫 The-Art-of-Linear-Algebra-zh-CN.pdf。它解决的核心问题只有一个把抽象代数符号还原成看得见的空间操作。适合谁适合正在学线性代数但被公式绕晕的学生也适合做机器学习、图形学、信号处理需要回头补几何直觉的工程师。如果你只是应付考试这份材料帮不了你但如果你想真正理解为什么 SVD 能压缩图像、为什么特征向量在变换中方向不变那它值得花一个周末啃完。2. 把矩阵当变换看四个核心概念的几何直觉怎么建立2.1 向量不是箭头是基的线性组合大多数教材把向量画成带箭头的线段这没错但不够。更准确的理解是一个向量是一组基向量的线性组合。在二维标准基下向量 (3, 2) 的意思是“取 3 个 i 方向单位向量加上 2 个 j 方向单位向量”。这个视角一旦建立后面理解矩阵的列空间就顺了。我一般会建议读者先做一件事拿一张方格纸画两个基向量 i 和 j然后随便写一个 2x2 矩阵把它的两列分别当作新的 i 和 j 画出来。比如矩阵 [[2, 1], [1, 3]]第一列 (2, 1) 是变换后的 i第二列 (1, 3) 是变换后的 j。原来方格纸上的每一个点都按照这个新基重新定位。这就是矩阵作为线性变换的几何含义。这个操作不需要任何代码纸笔就能做。但如果你想批量验证可以用 Python 的 matplotlib 画出来import numpy as np import matplotlib.pyplot as plt # 原始基向量 i_base np.array([1, 0]) j_base np.array([0, 1]) # 变换矩阵列向量就是新基 A np.array([[2, 1], [1, 3]]) # 变换后的基向量 i_new A i_base j_new A j_base fig, ax plt.subplots(figsize(6, 6)) ax.quiver(0, 0, i_base[0], i_base[1], colorgray, anglesxy, scale_unitsxy, scale1, label原始 i) ax.quiver(0, 0, j_base[0], j_base[1], colorgray, anglesxy, scale_unitsxy, scale1, linestyle--, label原始 j) ax.quiver(0, 0, i_new[0], i_new[1], colorred, anglesxy, scale_unitsxy, scale1, label变换后 i) ax.quiver(0, 0, j_new[0], j_new[1], colorblue, anglesxy, scale_unitsxy, scale1, label变换后 j) ax.set_xlim(-1, 4) ax.set_ylim(-1, 4) ax.grid(True) ax.legend() plt.show()这段代码的逻辑很直接矩阵 A 的列向量就是变换后的基向量。参数上唯一需要注意的是scale_unitsxy和scale1不加这两个参数quiver 会自动缩放箭头长度看起来就不准了。画出来你会看到红色箭头和蓝色箭头张成了一个平行四边形原来单位正方形被拉伸成了这个形状。面积的变化倍数就是行列式的绝对值。2.2 矩阵乘法就是变换的复合理解了单个矩阵是变换矩阵乘法就顺理成章了A B 的意思是先对向量做 B 变换再做 A 变换。注意顺序从右往左读。很多人在这里翻车是因为把 A B 和 B A 当成一回事。实际上矩阵乘法不满足交换律几何上就是“先旋转再拉伸”和“先拉伸再旋转”结果不同。验证方法很简单用两个矩阵分别乘同一个向量看结果是否一致import numpy as np # 旋转 90 度 R np.array([[0, -1], [1, 0]]) # 沿 x 轴拉伸 2 倍 S np.array([[2, 0], [0, 1]]) v np.array([1, 1]) # 先旋转再拉伸 result1 S R v # 先拉伸再旋转 result2 R S v print(先旋转再拉伸:, result1) print(先拉伸再旋转:, result2)输出会告诉你两个结果不同。这个例子在可视化笔记里通常会用动画展示但代码验证更直接。参数上没什么可调的关键是理解矩阵乘法的顺序对应变换的先后。2.3 特征向量变换中方向不变的向量特征值和特征向量的定义是 Av λv意思是矩阵 A 作用在向量 v 上只改变长度不改变方向。几何直觉是在某个变换下大多数向量都会被“扭”到新方向但总有那么几个特殊方向变换只是把它们拉长或缩短。这些方向就是特征向量拉长缩短的倍数就是特征值。计算特征值通常解 det(A - λI) 0但手工算容易出错。用 numpy 验证import numpy as np A np.array([[2, 1], [1, 3]]) eigenvalues, eigenvectors np.linalg.eig(A) print(特征值:, eigenvalues) print(特征向量:\n, eigenvectors) # 验证 Av λv for i in range(len(eigenvalues)): v eigenvectors[:, i] lam eigenvalues[i] print(fAv: {A v}, λv: {lam * v})参数说明np.linalg.eig返回的特征向量是单位向量且按列排列。验证时注意浮点误差Av 和 λv 不会完全相等但差值在 1e-10 量级就正常。如果差得远检查矩阵是否可对角化。2.4 奇异值分解从任意矩阵到旋转-缩放-旋转SVD 是线性代数里最强大的工具之一公式是 A UΣV^T。几何解释是任何矩阵变换都可以分解为三步——先旋转V^T再沿坐标轴缩放Σ再旋转U。这个视角在图像压缩、推荐系统、降维里反复出现。用 numpy 做一次 SVD 并验证重构import numpy as np A np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) U, S, Vt np.linalg.svd(A) print(U 形状:, U.shape) print(奇异值:, S) print(Vt 形状:, Vt.shape) # 重构 Sigma np.zeros_like(A, dtypefloat) np.fill_diagonal(Sigma, S) A_reconstructed U Sigma Vt print(重构误差:, np.linalg.norm(A - A_reconstructed))参数上np.linalg.svd返回的 S 是奇异值向量不是矩阵需要自己填充成对角矩阵。重构误差应该在 1e-14 量级。如果要做降维只保留前 k 个奇异值把 U、Sigma、Vt 都截断到 k 列/行再乘回去就得到秩为 k 的近似。3. 用 Python 复现可视化笔记里的五个关键图3.1 环境准备与依赖版本要复现笔记里的图不需要装什么重型框架numpy 加 matplotlib 就够了。我一般会固定版本避免 API 变动导致图跑不出来pip install numpy1.26.4 matplotlib3.8.4这两个版本在 Python 3.10 到 3.12 上都验证过。不要用太老的 matplotlibquiver 的参数行为有变化。如果要用动画再加pip install pillow用于保存 GIF。3.2 画向量加法的平行四边形法则向量加法 a b 的几何意义是首尾相接或者平行四边形对角线。笔记里通常用两个箭头加虚线表示。代码实现import numpy as np import matplotlib.pyplot as plt a np.array([2, 1]) b np.array([1, 2]) c a b fig, ax plt.subplots(figsize(6, 6)) ax.quiver(0, 0, a[0], a[1], colorred, anglesxy, scale_unitsxy, scale1, labela) ax.quiver(0, 0, b[0], b[1], colorblue, anglesxy, scale_unitsxy, scale1, labelb) ax.quiver(0, 0, c[0], c[1], colorgreen, anglesxy, scale_unitsxy, scale1, labelab) # 画虚线平行四边形 ax.plot([a[0], c[0]], [a[1], c[1]], k--, linewidth0.8) ax.plot([b[0], c[0]], [b[1], c[1]], k--, linewidth0.8) ax.set_xlim(-0.5, 4) ax.set_ylim(-0.5, 4) ax.grid(True) ax.legend() plt.show()关键参数还是anglesxy, scale_unitsxy, scale1保证箭头按真实坐标画。虚线部分用plot手动补形成平行四边形。3.3 画矩阵变换前后的网格对比这个图最能体现矩阵作为变换的直觉。思路是画原始网格再画变换后的网格用子图并排。import numpy as np import matplotlib.pyplot as plt A np.array([[1.5, 0.5], [0.5, 1.5]]) # 生成网格点 x np.linspace(-2, 2, 9) y np.linspace(-2, 2, 9) X, Y np.meshgrid(x, y) points np.vstack([X.ravel(), Y.ravel()]) # 变换 transformed A points X_t transformed[0, :].reshape(X.shape) Y_t transformed[1, :].reshape(Y.shape) fig, axes plt.subplots(1, 2, figsize(12, 6)) for ax, Xp, Yp, title in zip(axes, [X, X_t], [Y, Y_t], [原始网格, 变换后网格]): for i in range(Xp.shape[0]): ax.plot(Xp[i, :], Yp[i, :], b-, linewidth0.5) for j in range(Xp.shape[1]): ax.plot(Xp[:, j], Yp[:, j], b-, linewidth0.5) ax.set_xlim(-4, 4) ax.set_ylim(-4, 4) ax.set_aspect(equal) ax.grid(True) ax.set_title(title) plt.show()参数说明np.meshgrid生成网格点A points对所有点一次性做变换。set_aspect(equal)很重要不然网格会被拉变形看不出真实变换效果。3.4 画特征向量的方向不变性特征向量的图要突出“方向不变”。做法是画一堆随机向量再画它们经过 A 变换后的结果用不同颜色标出特征向量方向。import numpy as np import matplotlib.pyplot as plt A np.array([[2, 1], [1, 3]]) eigenvalues, eigenvectors np.linalg.eig(A) fig, ax plt.subplots(figsize(6, 6)) # 随机向量 np.random.seed(42) for _ in range(20): v np.random.randn(2) v v / np.linalg.norm(v) Av A v ax.quiver(0, 0, v[0], v[1], colorgray, anglesxy, scale_unitsxy, scale1, alpha0.5) ax.quiver(0, 0, Av[0], Av[1], colororange, anglesxy, scale_unitsxy, scale1, alpha0.5) # 特征向量 colors [red, blue] for i in range(2): v eigenvectors[:, i] Av A v ax.quiver(0, 0, v[0], v[1], colorcolors[i], anglesxy, scale_unitsxy, scale1, linewidth2, labelf特征向量 {i1}) ax.quiver(0, 0, Av[0], Av[1], colorcolors[i], anglesxy, scale_unitsxy, scale1, linewidth2, linestyle--) ax.set_xlim(-3, 3) ax.set_ylim(-3, 3) ax.grid(True) ax.legend() plt.show()灰色是普通向量橙色是变换后的结果红色和蓝色是特征向量及其变换结果。你会看到特征向量的变换结果和原方向共线只是长度变了。3.5 画 SVD 的旋转-缩放-旋转三步分解SVD 可视化稍微复杂但拆成三步就清楚了。用单位圆上的点依次做 V^T、Σ、U 变换。import numpy as np import matplotlib.pyplot as plt A np.array([[2, 1], [1, 2]]) U, S, Vt np.linalg.svd(A) theta np.linspace(0, 2 * np.pi, 100) circle np.vstack([np.cos(theta), np.sin(theta)]) # 三步变换 step1 Vt circle step2 np.diag(S) step1 step3 U step2 fig, axes plt.subplots(1, 4, figsize(16, 4)) titles [单位圆, V^T 旋转, Σ 缩放, U 旋转] data [circle, step1, step2, step3] for ax, d, title in zip(axes, data, titles): ax.plot(d[0, :], d[1, :], b-, linewidth2) ax.set_xlim(-3, 3) ax.set_ylim(-3, 3) ax.set_aspect(equal) ax.grid(True) ax.set_title(title) plt.show()参数说明np.diag(S)把奇异值向量转成对角矩阵。四张图连起来看就是单位圆先旋转、再沿轴缩放成椭圆、再旋转的完整过程。这个图在笔记里通常是动画但静态四联图已经足够说明问题。4. 避坑与排查复现可视化时最容易翻车的五个地方4.1 箭头长度不对看起来和手算不一致现象用 quiver 画向量箭头长度和坐标值对不上比如 (2, 1) 画出来像 (1, 0.5)。原因是 quiver 默认会自动缩放箭头scale参数默认不是 1。解决显式设置anglesxy, scale_unitsxy, scale1。这三个参数缺一不可少一个都会导致比例失真。4.2 网格图被拉变形看不出旋转效果现象画矩阵变换后的网格明明矩阵有旋转分量但图看起来只是拉伸。原因是 matplotlib 默认的坐标轴比例不是 1:1x 轴和 y 轴单位长度不同。解决加ax.set_aspect(equal)。这个坑在画 SVD 和特征向量时尤其常见因为旋转在非等比坐标下会被视觉上“压扁”。4.3 特征向量顺序和特征值不对应现象用np.linalg.eig拿到特征值和特征向量后发现 Av 和 λv 对不上。原因是特征值数组和特征向量矩阵的列是按顺序对应的但如果你手动重排了特征值特征向量也要跟着重排。解决不要单独排序特征值要么同时排序要么直接用原始顺序验证。另外注意np.linalg.eig返回的特征向量是单位向量但符号可能和手算相反这是正常的。4.4 SVD 重构时维度不匹配现象用 U Sigma Vt 重构矩阵时报维度错误。原因是np.linalg.svd返回的 S 是长度为 min(m, n) 的向量而 Sigma 需要是 m x n 的矩阵。解决用np.zeros_like(A)创建全零矩阵再用np.fill_diagonal填充奇异值。如果 A 不是方阵注意 Sigma 的形状要和 A 一致。4.5 中文标签显示成方框现象图里写中文标题或图例显示出来是方框。原因是 matplotlib 默认字体不支持中文。解决在代码开头加两行配置plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] FalseSimHei 是 Windows 自带字体Linux 和 macOS 上可能需要换成Noto Sans CJK SC或PingFang SC。如果找不到字体用英文标签也能说明问题不必死磕中文。5. 从看懂到用上把几何直觉迁移到实际问题的三个技巧第一个技巧遇到任何矩阵先问它的列向量张成什么空间。列空间的维度就是矩阵的秩零空间告诉你哪些向量被压成了零。这个习惯一旦养成解线性方程组 Ax b 时你会先判断有没有解、有多少解而不是上来就高斯消元。我一般会拿一个 3x3 矩阵练手手动写出它的列向量画在三维坐标系里看它们是否共面。共面就是秩小于 3方程组可能无解或有无穷多解。第二个技巧用 SVD 的奇异值谱判断矩阵的“有效秩”。奇异值下降很快的矩阵往往可以用低秩近似压缩。图像处理里把一张灰度图做 SVD只保留前 10% 的奇异值重构出来的图肉眼几乎看不出差别但存储量降了一个数量级。你可以拿一张自己的照片试转成灰度矩阵做 SVD分别保留前 5、10、20、50 个奇异值看重构效果和压缩比。这个实验比任何理论都直观。第三个技巧把特征值当成系统的“固有频率”。在微分方程、振动分析、马尔可夫链里特征值决定了系统长期行为。特征值绝对值小于 1 的分量会衰减大于 1 的会发散等于 1 的会持续。做迭代算法时如果迭代矩阵的谱半径大于等于 1算法就不会收敛。这个判断比跑一百次实验都快。我自己的习惯是每学一个新矩阵分解就找一个实际数据跑一遍把中间结果画出来。看不懂公式的时候看图图看不懂的时候回去看公式。来回切换几次直觉就长出来了。希望帮到你。本文还有配套的精品资源点击获取