☰
机器学习笔记体系化整理:从线性回归到强化学习的知识框架与代码实现
2026/10/10 8:48:21 网站建设 项目流程

1. 从零散笔记到体系化知识:我为什么坚持整理完这套机器学习课程笔记

很多人学机器学习都有过类似的经历:视频看了一遍,公式推导跟着抄了一遍,当时觉得懂了,过两周再回头看,脑子里只剩几个模糊的名词。我最初也是这样,课程视频刷得飞快,笔记记了满满一本,但真正要动手做一个项目时,发现自己连损失函数怎么推导、正则化项为什么能防止过拟合都说不清楚。这种“假性掌握”的状态持续了挺长时间,直到我下定决心把这套经典机器学习课程的笔记从头到尾整理一遍,才算真正把知识串了起来。

这套笔记对应的课程内容覆盖了监督学习、无监督学习、学习理论、强化学习等几大板块,从线性回归、逻辑回归这些基础模型,一路讲到支持向量机、EM算法、主成分分析,再到Q-learning这样的强化学习入门内容。整理的过程不是简单地把板书抄下来,而是要把每个算法的来龙去脉、数学推导、适用场景、代码实现都梳理清楚。这件事听起来工程量很大,但做完之后收获远超预期——不仅知识体系变得清晰,连带着写代码、调参、看论文的效率都上了一个台阶。

这篇文章适合几类人看:正在学机器学习但感觉知识点散落一地的同学;已经学过一遍但想系统复习的从业者;以及想通过整理笔记来倒逼自己深入理解某个算法的人。我会把整理笔记过程中形成的结构框架、每个模块的核心要点、容易踩的坑、以及怎么把数学推导和代码实现对应起来这些经验,尽量完整地分享出来。不是那种“三天速成”的爽文,而是一个普通学习者一步步把知识啃下来的真实路径。

2. 笔记的整体骨架:怎么把几十个算法塞进一个不混乱的框架

2.1 按学习范式划分四大板块,而不是按课程顺序

刚开始整理的时候,我犯了一个错误:完全按照课程视频的顺序来组织笔记。结果就是线性回归后面跟着梯度下降,梯度下降后面又跳到逻辑回归,逻辑回归讲了一半又插进来牛顿法,整个笔记像一条被猫玩过的毛线团。后来我意识到,课程顺序是为了教学方便,但知识本身的逻辑结构不是线性的。于是我重新按学习范式把内容分成四大板块:

  • 监督学习:输入数据带有标签,目标是学一个从输入到输出的映射。包括线性回归、逻辑回归、广义线性模型、支持向量机、决策树、集成方法等。
  • 无监督学习:数据没有标签,目标是发现数据内在结构。包括K-means聚类、高斯混合模型、EM算法、主成分分析、独立成分分析等。
  • 学习理论:研究“为什么”的问题。包括偏差-方差分解、VC维、正则化、模型选择等。
  • 强化学习:智能体通过与环境交互来学习策略。包括马尔可夫决策过程、值迭代、策略迭代、Q-learning等。

这个划分方式的好处是,每个板块内部的算法之间有清晰的演进关系。比如监督学习里,线性回归是基础,逻辑回归是在它上面套了一个sigmoid函数来解决分类问题,广义线性模型又把两者统一到一个指数族分布框架下。这样整理下来,知识点不再是孤立的岛屿,而是一张有路径可循的地图。

2.2 每个算法笔记固定五个维度,避免遗漏关键信息

确定了板块之后,下一个问题是:每个算法具体要记什么?我试过好几种模板,最后固定下来五个维度,每个算法都按这个结构来整理:

  1. 问题定义:这个算法解决的是什么问题?输入输出分别是什么?有什么假设条件?
  2. 数学推导:从目标函数出发,一步步推导出参数更新公式或优化方法。这一步不能偷懒,必须自己动手推一遍。
  3. 概率解释:很多算法都可以从概率角度重新理解。比如线性回归对应高斯噪声下的最大似然估计,逻辑回归对应伯努利分布下的最大似然估计。有了概率视角,算法的适用条件就清楚了。
  4. 代码实现:用Python和NumPy从零实现一遍核心逻辑,不调库。这一步是检验是否真正理解的关键。
  5. 优缺点与适用场景:这个算法在什么数据规模、什么特征条件下表现好?有什么局限性?和同类算法相比如何选择?

这五个维度看起来简单,但坚持下来不容易。尤其是数学推导和代码实现这两步,经常需要反复查资料、反复调试。但正是这两步,把“看懂了”变成了“真的会了”。

2.3 用交叉引用把不同板块的知识点连起来

笔记整理到后期,我发现很多概念是跨板块出现的。比如正则化,在学习理论里是从结构风险最小化的角度讲的,在监督学习里是以L1/L2范数的形式出现的,在概率解释里又对应着高斯先验或拉普拉斯先验。如果每个板块各讲各的,读者(包括未来的自己)很容易把它们当成不同的东西。

我的做法是在笔记里大量使用交叉引用。比如在讲岭回归的时候,标注“参见学习理论章节中关于L2正则化的偏差-方差分析”;在讲EM算法的时候,标注“参见高斯混合模型章节中E步和M步的具体形式”。这样整本笔记就变成了一个网状结构,而不是四个孤立的板块。复习的时候,顺着一个概念可以跳到相关的好几个地方,理解会立体很多。

3. 监督学习笔记的整理要点:从线性回归到支持向量机

3.1 线性回归:别急着跳到代码,先把概率假设搞清楚

线性回归看起来简单,但它是后面很多算法的基石。我整理的时候,特意花了比较多时间在概率解释上。课程里通常先讲最小二乘的几何意义——把标签向量投影到特征矩阵的列空间上,然后给出正规方程。但如果不讲概率假设,很多人会误以为最小二乘是“拍脑袋”选的目标函数。

实际上,线性回归的概率模型是这样的:假设目标值由线性函数加上高斯噪声生成,即 ( y = \theta^T x + \epsilon ),其中 ( \epsilon \sim \mathcal{N}(0, \sigma^2) )。在这个假设下,对参数做最大似然估计,得到的恰好就是最小二乘的解。这个推导我完整地写在了笔记里,每一步都标注了用到的概率公式。做完这一步之后,再看逻辑回归、广义线性模型,就会发现它们都是同一个套路的变体:换一个噪声分布或输出分布,最大似然估计就给出不同的目标函数。

代码实现方面,我用NumPy写了两种解法:一种是直接算正规方程 ( \theta = (X^T X)^{-1} X^T y ),另一种是梯度下降。正规方程在特征维度不高的时候很方便,但需要求矩阵逆,当特征维度很大或者矩阵接近奇异时会出问题。梯度下降虽然需要调学习率,但更适合大规模数据。笔记里我把两种方法的代码都贴了出来,并对比了它们在同一个数据集上的收敛速度和最终结果。

提示:正规方程里的矩阵求逆在实际计算中通常用伪逆或者QR分解来代替,直接调np.linalg.inv在矩阵条件数很差的时候会数值不稳定。这一点在课程里可能不会强调,但自己写代码的时候一定要注意。

3.2 逻辑回归:从广义线性模型的角度理解sigmoid的来历

逻辑回归的笔记我改了三次才满意。第一次只是把sigmoid函数和交叉熵损失抄了一遍,第二次补上了梯度推导,第三次才真正从广义线性模型的角度把它讲清楚。广义线性模型有三个组成部分:输出分布属于指数族、线性预测子 ( \eta = \theta^T x )、以及连接函数 ( g ) 使得 ( E[y|x] = g^{-1}(\eta) )。对于二分类问题,输出服从伯努利分布,自然参数和均值之间的关系推导出来正好就是sigmoid函数。

这个视角的价值在于,它解释了为什么逻辑回归用sigmoid而不是别的函数。不是随便选的,而是伯努利分布作为指数族分布的自然结果。同样,如果输出是计数数据,假设泊松分布,推导出来的就是泊松回归。笔记里我把这个统一框架画成了一个表格,列出不同输出分布对应的连接函数和模型名称,一目了然。

代码实现上,逻辑回归的梯度更新公式和线性回归长得几乎一样:( \theta := \theta + \alpha (y - h_\theta(x)) x )。区别只在于 ( h_\theta(x) ) 从线性函数变成了sigmoid函数。这个相似性不是巧合,而是广义线性模型的结构决定的。我在笔记里特意把两个更新公式并排放在一起,标注出相同点和不同点,方便对比记忆。

3.3 支持向量机:最大间隔的几何直觉比推导更重要

支持向量机的数学推导是整套课程里比较重的部分,涉及拉格朗日对偶、KKT条件、核技巧等。我整理的时候,先把几何直觉讲清楚,再上数学。最大间隔分类器的核心思想很直观:在能把两类数据分开的所有超平面里,选那个离最近的数据点最远的。这个“最远”用函数间隔和几何间隔来量化,最终转化成一个带约束的优化问题。

对偶问题的推导我手推了三遍。第一遍跟着讲义走,第二遍合上讲义自己推,第三遍尝试用不同的符号体系重新推。三遍下来,对KKT条件的理解才比较扎实。笔记里我把推导过程分成了几个关键步骤:构造拉格朗日函数、对原始变量求偏导并令其为零、代回得到对偶问题、写出KKT条件。每一步都标注了“为什么可以这样做”的理由,比如为什么对偶问题更容易求解、为什么只有支持向量对应的拉格朗日乘子非零。

核技巧的部分,我重点整理了“核函数为什么能避免显式计算高维特征”这个点。很多人知道核函数好用,但说不清楚它怎么绕开维度灾难的。实际上,核函数直接计算两个样本在高维空间的内积,而不需要显式地把样本映射到高维。笔记里我用一个简单的多项式核例子,手算了一遍核矩阵,对比了显式映射的计算量,差异非常直观。

代码实现方面,我用NumPy写了一个简化版的SMO算法来求解对偶问题。完整版的SMO比较复杂,但核心思想就是每次选两个乘子来优化,保持约束条件满足。我实现的版本在小型数据集上能跑通,和sklearn的结果对比误差在可接受范围内。这个过程让我对支持向量机的理解从“知道公式”变成了“知道怎么算出来”。

4. 无监督学习与学习理论:那些容易被跳过但极其重要的部分

4.1 EM算法:从“鸡生蛋蛋生鸡”到单调收敛的证明

EM算法是我整理笔记时花时间最多的一个主题。它的核心思想可以用一句话概括:当数据含有隐变量时,直接最大化似然函数很困难,但如果在给定当前参数估计的情况下,先计算隐变量的期望(E步),再最大化这个期望(M步),就能一步步逼近局部最优。这个“鸡生蛋蛋生鸡”的迭代过程,第一次看会觉得有点绕。

我整理的时候,重点做了两件事。第一件是把EM算法的一般形式推导清楚:从对数似然函数出发,利用Jensen不等式构造一个下界,然后证明E步是在最大化这个下界,M步是在最大化似然函数。这个推导的关键在于理解“下界”和“原函数”的关系。笔记里我画了一个示意图(用文字描述),展示每次迭代时下界如何抬升、原函数如何跟着上升,最终收敛到局部最优。

第二件事是用高斯混合模型作为具体例子,把E步和M步的公式完整推导了一遍。E步计算每个样本属于每个高斯分量的后验概率,M步用这些后验概率作为权重来更新均值、协方差和混合系数。推导过程中用到了多元高斯分布的概率密度函数、矩阵求导等知识,我把每一步的中间结果都写了出来,方便以后复习时快速回忆。

代码实现上,我写了一个二维高斯混合模型的完整实现,包括参数初始化、E步、M步、收敛判断。跑在一个模拟数据集上,能够正确地把两个重叠的高斯分量分开。这个实现让我对EM算法的收敛行为有了直观感受:初始值不同,收敛到的局部最优可能不同,所以实际应用中通常需要多跑几次取最好的结果。

4.2 主成分分析:两种推导路径的对比

主成分分析的笔记我整理了两种推导路径。第一种是从最大化投影方差的角度出发:找到一组正交方向,使得数据投影到这些方向上的方差依次最大。第二种是从最小化重构误差的角度出发:找到一组正交方向,使得数据投影后再重构回来的误差最小。这两种路径最终得到相同的解,但直觉不同。

第一种路径的推导用到了拉格朗日乘子法,最终归结为求协方差矩阵的特征值分解。第二种路径的推导用到了矩阵的迹的性质,最终也归结为同样的特征值问题。笔记里我把两种推导并排放在一起,标注出它们在哪个步骤分叉、又在哪个步骤汇合。这种对比让我对主成分分析的理解不再停留在“调用sklearn.decomposition.PCA”的层面。

实际应用方面,我整理了主成分分析的几个常见用途:数据可视化(降到二维或三维)、去噪(丢弃小特征值对应的方向)、特征压缩(减少后续模型的输入维度)。同时也标注了注意事项:主成分分析对特征的尺度敏感,使用前通常需要标准化;主成分是原始特征的线性组合,解释性不如原始特征直观;如果数据本身是非线性的,主成分分析可能效果不好,需要考虑核主成分分析或其他非线性降维方法。

4.3 学习理论:偏差-方差分解的直观理解

学习理论这部分在课程里往往比较靠后,很多人学到那里已经累了,容易草草跳过。但我整理下来发现,这部分恰恰是连接“算法”和“实践”的桥梁。偏差-方差分解就是一个典型例子。它把模型的期望泛化误差拆成三部分:偏差的平方、方差、以及不可约噪声。偏差衡量模型预测的平均值偏离真实值的程度,方差衡量模型预测的波动程度。

这个分解的推导涉及期望的运算,我一步步写在了笔记里。推导本身不难,难的是把结论和实际调参对应起来。比如,为什么增加模型复杂度通常会降低偏差但增加方差?为什么正则化能降低方差但可能增加偏差?为什么集成方法(如随机森林)能同时控制偏差和方差?这些问题在笔记里我都结合具体算法做了分析。

VC维的部分我整理得相对简略,因为完整的VC维计算对大多数实践者来说过于理论化。但我保留了核心结论:VC维衡量的是假设空间的容量,容量越大,模型越容易过拟合。实际中更常用的是用交叉验证来估计泛化误差,而不是去算VC维。笔记里我标注了这一点,避免自己在理论上钻得太深而忽略了实用工具。

5. 把数学公式变成可运行代码:我的实操流程与踩坑记录

5.1 从公式到代码的翻译规则

数学推导和代码实现之间有一道鸿沟,尤其是涉及矩阵运算的时候。我总结了几条翻译规则,写在笔记的开头部分,每次写新算法代码之前都先看一遍:

  • 求和符号对应循环或矩阵乘法:( \sum_i x_i ) 在代码里可能是np.sum(x),也可能是x @ np.ones(n),取决于上下文。如果是 ( \sum_i x_i y_i ),优先考虑x @ y而不是循环。
  • 矩阵转置要小心维度:公式里的 ( X^T ) 在代码里是X.T,但要注意X的每一行是一个样本还是每一列是一个样本。我习惯让X的每一行是一个样本,每一列是一个特征,这样 ( X\theta ) 直接得到预测值。
  • 向量化优先:能不用循环就不用循环。NumPy的广播机制可以处理很多看似需要循环的操作。比如计算所有样本的梯度,可以用X.T @ (y - h)一次性算出来。
  • 数值稳定性:涉及概率的地方,尽量在对数空间计算。比如计算似然函数时,先取对数再求和,避免连乘导致下溢。sigmoid函数在输入很大或很小时要防止溢出,可以用分段实现。

这些规则看起来琐碎,但实际写代码的时候能省很多调试时间。我在笔记里每个算法都附上了核心代码片段,并标注了对应的数学公式,方便对照。

5.2 调试梯度下降的三个实用技巧

梯度下降是很多算法的核心优化方法,但调试起来经常让人头疼。我整理了三个自己常用的技巧:

第一个技巧:用数值梯度检验解析梯度。对于任何自己推导的梯度公式,都可以用数值近似来验证。具体做法是:对每个参数,分别加上和减去一个很小的数 ( \epsilon ),计算损失函数的变化,除以 ( 2\epsilon ) 得到数值梯度。然后和自己推导的解析梯度对比,如果相对误差在 ( 10^{-6} ) 以下,说明推导正确。这个技巧帮我抓出了好几次推导中的符号错误。

第二个技巧:监控损失函数曲线。正常的梯度下降,损失函数应该单调下降(除非学习率太大导致震荡)。如果损失函数上升或者震荡,首先检查学习率是不是太大,然后检查梯度符号是不是反了。我在笔记里贴了一张自己调试时的损失曲线图(用文字描述),展示了学习率过大、过小、合适三种情况下的曲线形态。

第三个技巧:从小数据集开始。先用几十个样本的数据集跑通,确认算法逻辑正确,再换到完整数据集。小数据集上可以打印中间变量,方便定位问题。完整数据集上跑一次可能要几分钟,调试效率太低。

5.3 那些课程里不会讲但实际会遇到的坑

整理笔记的过程中,我踩了不少坑,这里挑几个有代表性的分享一下。

坑一:特征缩放没做,梯度下降收敛极慢。如果不同特征的量纲差异很大,比如一个特征在0到1之间,另一个在0到10000之间,损失函数的等高线会变成很扁的椭圆,梯度下降会来回震荡,收敛很慢。解决办法是标准化或归一化。我在笔记里标注了:除了决策树和随机森林这类基于分裂的模型,大多数模型都需要特征缩放。

坑二:正则化项没有排除偏置项。L2正则化通常只对权重施加,不对偏置施加。如果偏置也被正则化,模型会倾向于把偏置压到零,导致拟合能力下降。这个细节在公式推导时容易忽略,因为偏置通常被合并到参数向量里一起写了。我在代码实现时特意把偏置单独拿出来,不参与正则化。

坑三:交叉验证的数据泄露。做特征选择或标准化的时候,如果先在整个数据集上计算均值和方差,再划分训练集和验证集,就会造成数据泄露。正确的做法是在训练集上计算这些统计量,然后应用到验证集。这个坑我在整理学习理论部分时才意识到,之前做项目的时候一直没注意。

坑四:EM算法的初始值选择。EM算法收敛到局部最优,初始值不同结果可能差很多。实践中常用的做法是用K-means先跑一遍,用聚类结果来初始化高斯混合模型的参数。或者多随机初始化几次,选似然函数最大的那个。我在笔记里把这两种策略都写了进去。

6. 笔记整理完之后,我的学习方式发生了什么变化

6.1 从“收藏夹吃灰”到“主动输出”

以前看到好的文章或视频,第一反应是收藏,然后就没有然后了。整理这套笔记之后,我养成了一个习惯:学任何新东西,都尝试用自己的话写一遍。写不出来,说明没真懂。这个习惯倒逼我在看资料的时候主动思考:这个概念的动机是什么?它和我知道的什么东西有联系?如果让我给别人讲,我会怎么讲?

笔记整理到后期,我甚至开始给几个同学做小范围的讲解。讲的过程中,经常被问到一些自己没想过的问题,比如“为什么对偶问题里只有支持向量的乘子非零”“为什么主成分分析的特征向量要按特征值从大到小排列”。这些问题逼着我回去重新翻笔记、查资料,理解又深了一层。

6.2 看论文和调库代码时更有方向感

整理完监督学习和无监督学习的主要算法之后,再看一些机器学习相关的论文,感觉完全不一样了。以前看论文,看到公式就跳过,只看实验部分。现在看到公式,会下意识地去想:这个目标函数对应什么概率假设?优化方法是什么?和我知道的哪个算法有联系?这种“带着框架去读”的方式,效率高了很多。

调库代码的时候也是。以前用sklearn,就是看文档、调参数、跑结果。现在会去想:这个参数对应公式里的哪一项?改变它会怎样影响偏差和方差?比如LogisticRegression的C参数,其实就是正则化强度的倒数。理解了这一点,调参的时候就不是盲目试,而是有方向地调整。

6.3 对“学不完”这件事不再焦虑

机器学习领域发展很快,新模型、新方法层出不穷。以前总有一种“学不完”的焦虑,觉得要学的东西太多了。整理完这套经典课程的笔记之后,这种焦虑减轻了很多。因为很多新方法都是在经典方法的基础上改进的。比如深度学习里的各种网络结构,底层还是线性层、非线性激活、损失函数、梯度下降这些基本组件。理解了经典方法,再看新东西,能更快地抓住核心。

笔记整理完之后,我把它分享给了几个正在学的朋友。他们的反馈也让我意识到,整理笔记这件事的价值不仅在于自己学会了,还在于给别人提供了一个可以参考的路径。当然,每个人的知识背景和学习习惯不同,我的框架不一定适合所有人,但至少提供了一种可能性。

最后分享一个小心得:整理笔记的时候,不要追求一次完美。我第一版笔记有很多错误和遗漏,后来在复习和使用的过程中不断修正。笔记是活的,随着理解加深会不断更新。如果一开始就想着“等我把所有细节都搞清楚了再写”,可能永远写不完。先写一个粗糙的版本,然后在用的过程中慢慢打磨,这样更容易坚持下来。

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

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

立即咨询