机器学习线性代数基础:Python代码实战解析
2026/9/8 2:54:32 网站建设 项目流程

简介:这份资源是《机器学习线性代数基础(Python语言描述)》一书的配套代码包,适合正在学习机器学习数学基础、希望用Python动手验证线性代数概念的读者。压缩包共53个文件,以50个.py脚本为核心,辅以1份docx格式的Numpy科学计算库说明、1个score.csv数据文件及1张test.PNG示例图,资源整体仅2.48MB,轻量便携。代码按第1章至第7章组织,覆盖向量、矩阵、特征值、SVD等核心知识点,每章提供多个示例程序,可直接运行并对照观察输出,帮助理解抽象理论与代码实现之间的对应关系。对于阅读原书时希望边学边练、快速跑通示例的读者,这套代码能有效节省手动敲码时间,并可作为自行扩展实验的起点。目前已有179人浏览学习,适合作为配套自学参考资源。 拿到张雨萌老师的《机器学习线性代数基础(Python语言描述)》配套代码时,我最直观的感受是:这本书终于把“数学书”和“代码书”的边界打通了。国内讲机器学习的教材不少,但涉及数学基础时,大多数要么直接堆公式推导,要么一笔带过让你去看线性代数课本,真正愿意用Python代码把抽象概念一个个“跑”出来给你看的,确实不多。而这套配套代码的价值就在于:它把向量、矩阵、特征分解、SVD这些机器学习里高频使用的数学工具,变成了你可以亲手修改、运行、观察输出的实验对象。

我身边有不少朋友在入门机器学习时,卡住的往往不是算法本身,而是算法背后那一堆矩阵运算和范数符号。你用numpy调一行np.linalg.eig()毫不费力,但不明白特征值到底在“分解”什么,换到推荐系统、PCA降维、PageRank这些场景时就会发虚。这套代码和书籍的搭配,实际是想解决一个问题:让机器学习的初学者能“肉眼看到”线性代数在算法里的具体作用。它适合三类人:一是刚接触机器学习、数学基础薄弱的自学者;二是想补线性代数短板、准备面试的求职者;三是教学场景里需要大量示例代码的讲师或培训老师。

接下来我会基于这套代码的实际内容,从环境搭建、核心模块拆解、实操过程到常见问题,完整梳理一遍这套代码的正确打开方式。

1. 配套代码到底在讲什么:从抽象符号到可运行实验

1.1 机器学习里的线性代数为什么绕不开

绝大多数机器学习算法,最终都能归结为“对矩阵和向量做计算”。线性回归是求解线性方程组的近似解,PCA是求协方差矩阵的特征向量,神经网络的正向传播本质上是矩阵连乘,注意力机制里那堆QKV依然是向量内积和缩放。可以说,线性代数就是机器学习算法的“底层汇编语言”。

但这门语言有一个比较麻烦的特点:教材上的符号系统太抽象了。A^T A||x||_2λ_max,这些符号在纸面上推导一百遍,你可能依然想象不出它们在数据里到底提取了什么。而Python配套代码的好处在于,你可以直接构造一个真实的矩阵,调用SVD分解,然后把分解出来的U、Σ、V矩阵打印出来,甚至画成图,直观看到奇异值是怎么从大到小排列的、前几个奇异值对应的向量又捕获了什么结构。这种“符号变成数据、公式变成输出”的转变,是这套代码最大的价值。

1.2 配书代码的学习价值:不是“抄一遍”而是“改一遍”

很多学习者拿到配套代码后,习惯的做法是jupyter notebook里从上到下运行一遍,看到输出结果和书上一模一样,就觉得自己“会了”。但根据我自己带人的经验,哪怕把代码抄写十遍,不如认真改动一个参数、观察结果变化来得好。

这套代码在设计上其实留了不少“可动手”的口子。比如在讲解向量内积和夹角时,代码往往会构造两个具体向量,然后输出夹角余弦值。你可以把其中一个向量换成零向量,看看会发生什么;或者把二维向量扩展到三维、四维,验证高维空间里“所有向量都近乎正交”这个反直觉的结论。配套代码不只是一个标准答案库,更是一组实验脚手架——用好了,你等于拥有一个小型线性代数实验室。

2. 跑通配套代码前的环境准备:Python工具链的那些“坑”

2.1 Python版本与核心依赖库选择

这套配套代码基于Python编写,核心依赖是numpymatplotlib,部分章节可能用到scikit-learnpandas。我在实际安装和复现过程中,环境配置这块确实踩过一些坑,整理一下供大家参考。

  • Python版本:建议使用Python 3.8到3.11之间的版本。太老的版本(如3.6)在安装新版numpy时可能找不到预编译包,太新的版本(如3.12+刚发布时)则可能遇到某些依赖库尚未适配的情况。
  • numpy版本:不要盲目追求最新版。numpy 1.21到1.24之间比较稳定,如果安装了numpy 2.x,某些老代码中使用的np.floatnp.int这类别名会直接报错,这是最常见的兼容性问题。
  • matplotlib:建议使用3.5以上版本,绘图接口和中文支持更完善。
  • 其他可选依赖:如果你想把书里某些图形画得更丰富,可以安装seaborn做统计图美化;如果涉及PCA应用,scikit-learn会非常方便。

安装命令可以直接用:

pip install numpy matplotlib scikit-learn

如果你在国内容器环境或内网环境安装,建议配置好镜像源,用清华或阿里云的PyPI镜像能省去不少超时重试的烦恼。安装完成后,执行下面这段代码可以快速验证环境是否正常:

import numpy as np import matplotlib.pyplot as plt a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) print("向量内积:", np.dot(a, b)) # 简单绘图验证 plt.plot([0, a[0]], [0, a[1]], label='a') plt.axis('equal') plt.legend() plt.show()

如果内积输出32,并且能弹出坐标轴图形,说明环境基本OK。这里有两个细节值得注意:一是我建议用conda创建独立虚拟环境,不要直接装在系统全局,因为后面你肯定会装PyTorch、TensorFlow这类重量级库,互相污染版本是家常便饭;二是绘图时如果中文显示为方块,需要额外设置中文字体,后面我会专门讲这个问题。

2.2 推荐的IDE和运行方式:Jupyter Notebook是首选

配书代码的定位是“边看边实验”,所以强烈推荐使用Jupyter Notebook或Jupyter Lab来运行。原因很简单:线性代数的学习强调“分步观察”——一个矩阵分解过程,你拆成六个单元格逐个运行,每一步都能查看中间矩阵的形态;直接用.py脚本一次性跑完,观察粒度就太粗了。

如果你之前只装了Anaconda,打开Anaconda Prompt后输入:

jupyter lab

浏览器会自动弹出工作台界面。在界面里新建一个Python 3内核的Notebook,然后把你下载的配套代码.ipynb文件上传进去,逐个单元运行即可。

如果遇到内核一直连不上或卡死,多半是pyzmq版本冲突。解决方法是:

pip install --upgrade pyzmq

另外vscode也是不错的选择,安装Python插件和Jupyter插件后,可以直接在.ipynb文件里运行单元格,而且调试功能比浏览器版Jupyter强很多,适合需要单步跟踪的问题。不过对于首次接触这套代码的人,Jupyter Notebook的简洁界面会更友好,不会一开始就被工具栏和配置文件劝退。

3. 核心模块拆解:这套代码里最值得反复研究的几块内容

3.1 向量与矩阵的表示:从Python列表到numpy数组

配书代码最开始的部分,通常是从“如何用Python代码表示向量和矩阵”切入的。初学者容易把思维停留在小学算术层面,用列表套列表硬造矩阵。但实际上,numpy数组和Python列表的根本区别在于:numpy数组支持向量化计算和广播机制

比如计算两个向量逐元素相乘,用列表推导式你要写:

c = [a[i] * b[i] for i in range(len(a))]

而用numpy数组只需要:

c = a * b

代码量少了,更关键的是性能差异——数据规模到百万级时,向量化计算可能会快几十倍。配书代码在向量内积、矩阵乘法、转置、逆矩阵这些基础操作上都会给出对比示例,我建议你在跑这些代码时,特意关注shape属性。一个维度对不上的矩阵相乘会报ValueError,这个报错几乎是你未来跟numpy打交道时最常遇到的“朋友”——通过反复调整维度来理解“矩阵乘法要求左矩阵列数等于右矩阵行数”这个规则,比背十遍定义都管用。

3.2 范数、内积与正交性:理解距离和角度的几何意义

机器学习模型里,范数几乎是度量一切的工具:误差是范数,正则化是范数,向量的“大小”也是范数。配书代码在范数部分通常会演示np.linalg.norm()的多种用法,比如计算二范数、一范数和无穷范数。

我建议你在跑这部分代码时,特别关注一个容易被忽略的概念:单位向量与向量单位化。代码里可能会出现把任意向量除以它的范数、得到一个方向相同但长度为1的向量的过程。这在机器学习的特征缩放、权重初始化里都有直接应用。配合matplotlib画出原始向量和单位向量的对比图,那种“向量方向不变但大小归一”的几何直觉会一下子建立起来。

正交性的部分同样值得深挖。正交向量意味着内积为零,也就意味着两向量之间没有线性相关性。配书代码会用一组例子展示:正交基在高维空间中具有很好的独立性,可以简化很多计算。PCA主成分分析的核心,其实就是在数据协方差矩阵的特征向量中找出一组正交基,所以这一小节的铺垫意义重大。

3.3 特征分解与奇异值分解:机器学习的“隐藏引擎”

特征值分解和SVD是这套代码的“重头戏”,也是很多自学者最容易变成“调包侠”的部分。代码里会用np.linalg.eig()np.linalg.svd()对同一个矩阵做分解,然后详细展示分解结果的shape和数值。

这里有一个关键区别值得你反复实验:特征分解只适用于方阵,而SVD适用于任意矩阵。实际数据里,我们的特征矩阵大多是“样本数×特征数”的矩形,比如1000个样本、20个特征,那就是1000×20的矩阵,此时SVD才是通用的分解工具。配书代码通常会用一张图像(比如把图片变成像素矩阵)来做SVD,然后只保留前k个奇异值重建图像,让你直观看到“低秩近似”丢掉了什么、保留了什举。

这个实验效果非常震撼:k=10时图像还很模糊,k=50时已经能辨认轮廓,k=100时几乎接近原图。这个过程能让你理解为什么PCA能够降维——因为它本质上就是去掉那些奇异值很小、对整体结构贡献很低的方向。

4. 实操指南:从配书代码到自主实验的完整路径

4.1 五步跑通第一个SVD图像压缩实验

这里我以配书代码里最有趣的SVD图像压缩实验为例,讲解从准备数据到观察输出的完整流程。

第一步,准备数据。如果你不想找外部图片,直接用代码内置的小像素矩阵也完全够用。不过为了效果,我建议下载一张64×64的灰度图,转换成numpy数组:

from PIL import Image import numpy as np img = Image.open('sample.jpg').convert('L') A = np.array(img) print(A.shape) # (64, 64)

第二步,进行SVD分解:

U, S, Vt = np.linalg.svd(A)

注意这里S返回的是一维数组,而不是对角矩阵。如果需要矩阵形式,可以用np.diag(S)转换。

第三步,取前k个奇异值重建图像:

k = 10 A_reconstructed = U[:, :k] @ np.diag(S[:k]) @ Vt[:k, :]

这行代码就是SVD压缩的核心公式:A ≈ U_k Σ_k V_k^T。代码运行时可以打印S的前10个值,你会发现衰减非常快——第一个奇异值可能是几百,第二个就变成几十了,这正是图像中主要结构集中在前几个奇异值上的证据。

第四步,可视化对比。把原图和k取不同值的重建图并排画出来:

import matplotlib.pyplot as plt plt.figure(figsize=(8, 4)) plt.subplot(1, 3, 1) plt.imshow(A, cmap='gray') plt.title('Original') plt.subplot(1, 3, 2) plt.imshow(A_reconstructed, cmap='gray') plt.title(f'k={k}') plt.show()

第五步,观察并记录:k=10时图像保留了哪些信息?边缘是否锐利?奇异值小到多少时视觉上开始不可接受?把这些问题随手记录下来,就是一份非常好的学习笔记。如果你嫌计算太慢或内存占用大,可以用sklearn.utils.extmath.randomized_svd来做随机化SVD,大数据集上能提速不少。

4.2 可视化辅助理解:让抽象的数学“看得见”

配书代码里大量使用matplotlib绘制向量图、散点图和三维图,这一部分非常值得花时间逐行研究。

拿向量加法和线性组合来说,代码会画出两个箭头向量以及它们的和向量,运行之后你会“啊……”一声:原来平行四边形法则用坐标表示就是逐元素相加,没有任何神秘。再比如矩阵乘法,代码可以把矩阵视为线性变换,然后画出一组基向量(比如x轴和y轴的单位向量)在变换前后的位置变化。当矩阵的行列式为负时,你会看到基向量的“手性”翻转,这比单纯背公式理解深刻得多。

可视化还有一个实用小技巧:在Jupyter里用%matplotlib inline可以内嵌显示图形,但如果你想交互式旋转三维图,用%matplotlib notebook%matplotlib widget更合适。建议两个都试一下,找到自己舒服的交互模式。另外注意,如果图上中文显示为乱码方块,需要在代码开头加上:

import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] # 或用你系统里的中文字体名 plt.rcParams['axes.unicode_minus'] = False

第二条unicode_minus很关键,不设的话坐标轴的负号会显示成一个异常的方块。

5. 常见问题与排查技巧实录:照着这份清单能省一半时间

5.1 环境与依赖问题:报错多半就这几类

在带学员和实际复现过程中,我整理了这套配书代码最常遇到的几个环境类问题,集中放在下面:

问题现象可能原因解决方法
ModuleNotFoundError: No module named 'numpy'当前环境没有numpy或用了错误的conda环境conda activate 环境名后重新pip install numpy
AttributeError: module 'numpy' has no attribute 'float'numpy 2.x移除了旧别名安装numpy==1.24.3或把代码里的np.float改成float
中文字体显示为方块matplotlib默认字体不含中文使用plt.rcParams['font.sans-serif'] = ['SimHei']配置
ValueError: shapes (m,n) and (p,q) not aligned矩阵乘法的维度不匹配打印两个矩阵的shape,检查是否满足左列=右行
Jupyter内核频繁崩溃pyzmq版本冲突或内存不足升级pyzmq;减少一次性创建的矩阵规模
LinAlgError: Matrix is singular矩阵不可逆,行列式为0检查是否有重复行/列;加上微小单位阵扰动后再求逆

遇到过多次的情况是:初学者在conda的base环境里运行,但base环境里的Python是系统的,pip却是另一个路径的。建议所有项目都用独立环境管理,不要默认用base。

5.2 理论与实践衔接的误区:代码跑通不等于学会

运行代码环节没问题之后,真正的难点出现在“动手写自己的代码”时。比如配书代码里讲完特征分解后,会布置一个“用特征分解求矩阵的n次幂”的小练习。很多学员直接对矩阵做特征分解,然后取np.diag(S)**n,却忘记要乘回特征向量矩阵。这暴露出一个常见误区:知道API的用法,但不理解API背后的数学流程

我建议你学每一节时都问自己三个问题:这里的输入是什么?输出是什么?中间走过了什么步骤?如果能把三个问题口述清楚,说明确实掌握了,而不是只“见过”这段代码。还有一个不错的检验方法:把代码里的示例矩阵换成实际业务数据。比如你本来在二维人造数据上跑PCA,试着把它换成手写数字数据集里的某张图片,一样能降维,而且重构效果更直观。这种迁移实验做上两三次,理论和实践才算真正焊在了一起。

写在最后:这套代码我推荐怎么用

根据我带过的学员和我自己重读这本书的经验,一套比较有效的学习路线是:先不看代码,把书上每章后面的思考题自己拿纸推一遍,然后打开配套代码,把推不出来的地方在代码里画图观察;接着随意改参数,观察输出的变化;最后合上代码,从头自己实现一遍核心函数,哪怕是直接调用numpy也比你复制粘贴收获大得多。

我在实际使用中发现,这套代码的很多范例用了很多人造小数据,图形好看、规律明显,但它和真实世界的“脏数据”之间还有一段距离。所以学完之后,一定要自己去UCI或Kaggle找一个真实数据集,把书里的PCA、SVD、线性回归这些方法套上去跑一遍。只有真正从混乱数据中提取出有意义的结构,你才会理解线性代数为机器学习提供的那套“坐标系统”到底有多重要。

最后分享一个我自己的小习惯:每学完一个概念,就在笔记本上画一个“数学符号↔numpy函数↔算法场景”的映射表。比如λ_max ↔ np.linalg.eigvals(A).max() ↔ PageRank主特征向量||x||_2 ↔ np.linalg.norm(x) ↔ MSE误差计算。这个表整理完,你会发现机器学习的很多公式突然变得具体起来——原来每个数学符号背后都有一个Python函数在等着你,而配书代码,就是帮你建立这些映射的最好起点。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询