吴恩达机器学习(新版):第二门课(下) · 机器学习实践与决策树

本电子书由视频课程重构而成(个人学习用)。 课程视频、字幕与讲义版权归 DeepLearning.AI / Stanford 所有。本电子书仅为个人学习所做的中文书面重构,不得用于任何商业用途或公开传播。书中截图取自对应分P视频画面,并标注「分P @ 时间」以便回源核对。

原课程 Machine Learning Specialization(DeepLearning.AI / Stanford Online,2022 新版),讲师 Andrew Ng(吴恩达)
视频来源 Bilibili 搬运合集 BV16jyuBBEom(本册为第二门课的实践方法 + 决策树部分,分P p71–p100)
官方配套 https://www.deeplearning.ai/specializations/machine-learning
参考笔记(2014 版课程) https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes

制作模型:deepseek-flash(coding-agent / pi;据 ~/.pi/agent/settings.json)


本册导读

第二门课的内容横跨两个相当不同的主题。本册专注"把机器学习真正用好"的方法论,以及决策树,覆盖:

  1. 机器学习诊断:下一步做什么(p71–p73)
  2. 偏差与方差(p74–p79)
  3. 机器学习项目的迭代开发:误差分析、数据、迁移学习、完整周期、伦理(p80–p85)
  4. 倾斜数据集与精确率/召回率(p86–p87)
  5. 决策树(p88–p89)
  6. 决策树学习算法:熵、信息增益、独热编码、连续特征、回归树(p90–p95)
  7. 集成学习:随机森林与 XGBoost(p96–p100)

配套的另一册《神经网络与深度学习》覆盖神经网络的前向传播、TensorFlow 实现、训练、激活函数、Softmax、Adam 等。


第一章 机器学习诊断:下一步做什么

(对应模块 11,视频 p71–p73)

1.1 核心问题:下一步做什么

(p71)

现实中:训练好的模型几乎从来不会第一次就表现得好。构建 ML 系统的关键,是决定下一步做什么来提升性能。

吴恩达见过一些团队花 6 个月做出来的东西,更有经验的团队几周就能完成——差别就在于能否高效地反复做对"下一步"的决定。

以"已实现正则化线性回归来预测房价,但预测误差大得无法接受"为例,你至少有 6 个方向可试:

  1. 获取更多训练样本;
  2. 减少特征(用小一点的特征集);
  3. 增加特征(找房屋的其他属性);
  4. 增加多项式特征(x₁², x₂², x₁x₂…);
  5. 减小 λ;
  6. 增大 λ。

问题在于:其中一些有用,一些纯属浪费时间。有人花好几周收集数据,结果毫无提升;有时确实有帮助,有时没有。

所以我们需要诊断(diagnostics)——某些测试能深入揭示算法的问题、指导该往哪投入时间。学习如何做诊断、如何运行它们,是本门课的核心之一。跑诊断要花时间,但常常能省下几个月。

面对误差,你有 6 个可能方向,但需要用

📷 面对误差,你有 6 个可能方向,但需要用"诊断"来确定哪个有用
回到原视频 (00:01:19)

1.2 用训练集/测试集评估模型

(p72)

当特征多于一两个时,画不出 f(x)(四维函数怎么画?),所以需要更系统的评估方法。

做法:把数据分成训练集和测试集(如 70% / 30% 或 80% / 20%)。

符号:

回归用到的两个量(都不含正则化项,正则项只属于训练目标):

$$\begin{aligned}

J_{\text{train}}(w,b) &= \frac{1}{2m_{\text{train}}}\sum_{\text{训练集}}\big(f(x^{(i)}) - y^{(i)}\big)^2\ J_{\text{test}}(w,b) &= \frac{1}{2m_{\text{test}}}\sum_{\text{测试集}}\big(f(x^{(i)}) - y^{(i)}\big)^2

\end{aligned}$$

例(四阶多项式、5 个点的训练集):它能完美拟合训练集,所以 J_train ≈ 0;但曲线剧烈波动、泛化差,遇到训练集之外的样本预测与真实值差距很大,所以 J_test 很高。这告诉你:训练误差低不代表泛化好。

分类问题:常用另一套定义——用误分类比例(预测 ŷ≠y 的样本占比)作为 J_train、J_test。例如 0/1 数字分类,J_test = "测试集中把 0 判成 1 或把 1 判成 0 的比例"。

把数据分成训练集/测试集,用 J_train 与 J_test 评估

📷 把数据分成训练集/测试集,用 J_train 与 J_test 评估
回到原视频 (00:02:01)

1.3 模型选择与交叉验证集

(p73)

要选"多项式阶数 d"(或其他模型/超参数)时,直接用测试集去挑是有缺陷的。

为什么?因为你把 d 也"拟合"到了测试集上:你挑了让 J_test 最小的 d,于是这个 J_test 会过于乐观(低于真实泛化误差)。这和"用训练集估计泛化误差会过于乐观"是同一个道理。

正确做法:把数据分成三份:

子集 用途 常见比例
训练集(train) 拟合参数 w、b 60%
交叉验证集(cross-validation / 验证集 validation / 开发集 dev) 选择模型与超参数(d、λ、网络结构…) 20%
测试集(test) 最后评估泛化误差 20%

交叉验证集有几个名字:验证集(validation set)、开发集(dev set)——意思相同。吴恩达个人最常用"开发集",因为念起来最短。

三个误差:

模型选择流程:

  1. 对每个候选模型(d=1,2,…,10),在训练集上拟合参数;
  2. 在交叉验证集上算 J_cv;
  3. 选 J_cv 最低的模型;
  4. 最后在测试集上评估一次,报告 J_test 作为泛化误差的估计。

黄金法则:

所有关于模型/算法的决定(选参数、选多项式阶数、选网络架构)都只用训练集和交叉验证集;测试集在做完所有决定之后才用,且只用一次。

这样才能保证测试集给出不偏乐观的泛化误差估计。

编者拓展|一个极其常见的坑:数据泄漏(data leakage):上面这条「黄金法则」之所以重要,是因为一旦你在做任何决定之前就看过测试集(哪怕只是「试了几次觉得哪版更好」),测试集就被间接拟合了,它给出的性能会偏乐观——等真上线,效果会明显变差。更隐蔽的一种是特征泄漏:某个特征在训练时「偷看」了标签。记住:测试集只用一次,且只用于最终报告。这个流程同样适用于选择神经网络架构(小/中/大网络,或不同的层数/单元数)——用 J_cv 选,最后用测试集报告。

模型选择:训练集拟合、交叉验证集选模型、测试集最终评估

📷 模型选择:训练集拟合、交叉验证集选模型、测试集最终评估
回到原视频 (00:05:13)


第二章 偏差与方差

(对应模块 12,视频 p74–p79)

2.1 用 J_train 与 J_cv 诊断

(p74)

先回顾两个概念:

当特征很多、画不出 f(x) 时,用 J_train 与 J_cv 来诊断:

情况 判据
高偏差(欠拟合) J_train 很高(J_cv 也高,两者接近)
高方差(过拟合) J_cv 远大于 J_train(J_train 通常很低)
恰到好处 J_train 低,且 J_cv 与 J_train 接近(都不比对方差太多)
高偏差:J_train 很高(连训练集都拟合不好)

📷 高偏差:J_train 很高(连训练集都拟合不好)
回到原视频 (00:02:40)

高方差:J_cv 远大于 J_train

📷 高方差:J_cv 远大于 J_train
回到原视频 (00:03:07)

2.2 偏差/方差随模型复杂度的变化

数学角落(偏差-方差分解):对重复采样的数据集,预期测试误差可分解为

$$\mathbb{E}\big[(t-\hat y)^2\big]=\underbrace{\sigma^2}_{\text{不可约噪声}}+\underbrace{\big(\mathbb{E}[\hat y]-f^*\big)^2}_{\text{偏差}^2}+\underbrace{\mathbb{E}\big[(\hat y-\mathbb{E}[\hat y])^2\big]}_{\text{方差}}$$

画成「随模型复杂度变化」的曲线,就是经典的 U 形:左边偏差主导(欠拟合),右边方差主导(过拟合)。

(p74)

若把 J_train、J_cv 画成多项式阶数 d 的函数(不使用正则化时):

所以 J_cv 曲线的最低点对应"既没有高偏差也没有高方差"的模型。

J_train 与 J_cv 随多项式阶数 d 的变化:J_cv 先降后升

📷 J_train 与 J_cv 随多项式阶数 d 的变化:J_cv 先降后升
回到原视频 (00:05:06)

2.3 正则化与偏差/方差

易错点 M13:正则化的直接 mechanism 是「参数收缩(prefer small $\lVert w\rVert$)」;「方差 ↓、稳定性 ↑、偏差 ↑」是它的统计后果——不要把「降低 variance」当成正则化本身的偏好。

易错点 M14:$\lambda$ 大 → 约束强 → 高 bias → 欠拟合;$\lambda$ 小 → 约束弱 → 高 variance → 过拟合。别记反。

(p75)

λ 的选择决定了偏差与方差的平衡:

把 J_train、J_cv 画成 λ 的函数:

用交叉验证选 λ:试一系列 λ(如 0, 0.01, 0.02, 0.04, …, 10,每次翻倍),对每个 λ 拟合参数并算 J_cv,选 J_cv 最小的 λ,最后用测试集报告 J_test。

有趣的对照:λ 的曲线与 d 的曲线大致互为镜像——d 图里高方差在右、高偏差在左;λ 图里高方差在左、高偏差在右。但两者的解决办法一样:用交叉验证评估一系列取值,选最好的那个。

J_train 与 J_cv 随 λ 的变化:λ 太小过拟合、太大欠拟合

📷 J_train 与 J_cv 随 λ 的变化:λ 太小过拟合、太大欠拟合
回到原视频 (00:05:46)

2.4 建立"基准表现"再判断高低

(p76)

仅看"J_train 高不高"是不够的——"高"是相对什么而言? 需要一个参照。

以语音识别为例(目标:把音频转成文字;误差 = 转录不完全正确的比例):

单看 10.8% 好像"很高、像是高偏差"。但如果人类在这份音频上的错误率就有 10.6%(很多音频本身嘈杂、真的没人能准确转录),那么 10.8% 其实已经非常好。

所以引入"基准表现(baseline performance)"——你合理期望算法能达到的误差水平,例如:

判据变成:

在上面的例子里:J_train 只比人类差 0.2%(不算高偏差),但 J_cv 比 J_train 高 4% → 主要是高方差。

用基准表现判断:J_train−基准 看偏差,J_cv−J_train 看方差

📷 用基准表现判断:J_train−基准 看偏差,J_cv−J_train 看方差
回到原视频 (00:06:59)

2.5 学习曲线

(p77)

学习曲线:横轴是训练集大小 m,纵轴是误差;两条曲线是 J_train 与 J_cv。

基本形状:

高偏差(欠拟合)时的学习曲线:

所以在投入大量精力收集数据前,先检查是不是高偏差。

高方差(过拟合)时的学习曲线:

绘制学习曲线:取训练集的不同子集(100、200、300…个样本)分别训练,记录 J_train、J_cv。缺点是计算代价高(要训练很多个模型),所以实践中不常画,但脑子里有这张图对判断很有帮助。

高偏差的学习曲线:两条曲线都趋平且都很高,加数据帮助不大

📷 高偏差的学习曲线:两条曲线都趋平且都很高,加数据帮助不大
回到原视频 (00:03:39)

高方差的学习曲线:J_cv 远高于 J_train,加数据有帮助

📷 高方差的学习曲线:J_cv 远高于 J_train,加数据有帮助
回到原视频 (00:07:17)

2.6 回到"下一步做什么"

(p78)

现在可以把开头的 6 个方向按偏差/方差归类:

方向 主要解决
获取更多训练样本 高方差
尝试更小的特征集 高方差
增加(额外)特征 高偏差
增加多项式特征 高偏差
减小 λ 高偏差
增大 λ 高方差

概括成两条:

两个常见误区: * 不要为了修正高偏差而减少训练集——那只会让交叉验证误差更差; * 不要把"高方差"误当成"高偏差"。诊断对了,方向才对。

吴恩达引用一位博士生的说法:

"偏差-方差权衡是那种很快就能学会、却要用一生去掌握的概念。"

编者拓展|「权衡」二字的来历:经典统计学习理论里,模型复杂度与泛化误差的关系是一条 U 形曲线:复杂度太低 → 偏差主导(欠拟合);太高 → 方差主导(过拟合)。因为「降低偏差往往抬高方差、反之亦然」,所以叫偏差-方差权衡(bias-variance tradeoff)。本章后面的「神经网络 + 大数据」部分,正是要说明如何绕开这种痛苦权衡。

6 个方向按

📷 6 个方向按"解决高偏差 / 高方差"分类
回到原视频 (00:05:39)

2.7 神经网络与偏差/方差

(p79)

传统上人们讲"偏差-方差权衡":模型越简单偏差越高、越复杂方差越高,得在中间取平衡。但神经网络 + 大数据提供了一条新的路:

大型神经网络在小到中等规模数据上训练时,是"低偏差机器"——只要网络足够大(更多层 / 每层更多单元),几乎总能很好地拟合训练集。

一个很有效(但不总适用)的流程:

  1. 训练一个网络,问:它在训练集上表现好吗?(把 J_train 与基准比较)
  2. 不好(高偏差)→ 把网络变大(更多层/单元),重复,直到 J_train 与基准相当(约等于"拟合了训练集");
  3. 达标后,问:它在交叉验证集上表现好吗?
  4. 不好(J_cv 远高于 J_train,高方差)→ 获取更多数据,然后重复;
  5. 循环直到同时满足两者,就得到不错的模型。

核心洞察:用更大的网络几乎总能降偏差;用更多数据来降方差——不必像传统那样在两者间痛苦权衡。

注意:

大网络降偏差、更多数据降方差:摆脱

📷 大网络降偏差、更多数据降方差:摆脱"偏差-方差权衡"的新路径
回到原视频 (00:02:28)


第三章 机器学习项目的迭代开发

(对应模块 13,视频 p80–p85)

3.1 迭代循环

(p80)

开发 ML 系统是一个反复迭代的过程:

  1. 决定系统架构:选模型、决定用什么数据、可能还要选超参数;
  2. 实现并训练模型——几乎从来不会第一次就达到预期;
  3. 跑诊断:看偏差/方差(上一章)、做误差分析(下一节),也检查是否有代码 bug;
  4. 根据诊断决定下一步:增大网络?改 λ?加数据?加特征?减特征?
  5. 带着新的架构选择再循环——通常要迭代多次才能达到想要的性能。

"决定循环里下一步做什么"的效率,直接决定整个项目的速度。

ML 开发的迭代循环:设计 → 训练 → 诊断 → 决定下一步 → 再循环

📷 ML 开发的迭代循环:设计 → 训练 → 诊断 → 决定下一步 → 再循环
回到原视频 (00:01:12)

以垃圾邮件分类器为例:把邮件文本转成特征(如取最常见的 10,000 个英文单词,每个词对应一个 0/1 特征表示"是否出现";也可以记录出现次数,但 0/1 也能工作得不错)。用逻辑回归或神经网络训练后,若效果不佳,你有很多想法:

问题仍是:这么多想法,哪个更有希望? 选对方向能让项目快 10 倍;选错可能浪费数月。偏差/方差分析与误差分析,正是帮你筛选的工具。

3.2 误差分析

(p81)

误差分析(error analysis) 是仅次于偏差/方差的重要诊断手段:手动检查算法分错的样本,把它们归类到共同的主题/特征上,并统计数量。

例:500 个交叉验证样本中算法分错 100 个。逐个查看这 100 个并计数:

错误类型 数量
医药类垃圾邮件 21
钓鱼/窃取密码邮件 18
异常邮件路由 7
故意拼写错误 3
含图片的垃圾邮件 …

结论很直接:医药垃圾邮件和钓鱼邮件是大问题(应优先投入),而"故意拼写错误"虽然也是问题,但只占 3/100——即使你造出极其复杂的检测拼写错误的算法,也只能解决 3 个错误,净收益很小,不值得优先做。

(吴恩达坦言:他当年就花了很多时间做拼写错误检测,后来才意识到净影响很小——如果早做误差分析,就能省下那些时间。)

注意事项:

误差分析的价值:把"下一步做什么"从猜测变成有数据支撑的优先排序——例如决定"专门去收集更多医药垃圾邮件的数据",或"专门写检测钓鱼 URL 的特征"。

误差分析:手动统计每类错误的数量,据此排优先级

📷 误差分析:手动统计每类错误的数量,据此排优先级
回到原视频 (00:00:19)

3.3 添加数据

(p82)

更聚焦地补数据:与其"收集所有类型的数据"(慢且贵),不如根据误差分析只补有问题的那类。例如发现"医药垃圾邮件是主要错误"→ 专门去找更多医药垃圾邮件样本。若你有大量未标注数据,可让标注员专门挑出某类样本。

数据增强(data augmentation)——从已有样本变出新样本(对图像、音频尤其有用):

关键原则:

你施加的变形/噪声,必须能代表测试集里真实存在的类型才有效。

数据合成(data synthesis)——从零造全新样本:

从"模型中心"到"数据中心":过去几十年研究者习惯固定数据集、改进模型,于是我们有了一流的算法(线性回归、逻辑回归、神经网络、决策树)。但有时把精力放在数据上(收集特定类型的数据、数据增强、数据合成)反而更有效——这是一种数据驱动(data-centric)的方法。

数据增强:旋转/缩放图像,或给音频叠加背景噪音

📷 数据增强:旋转/缩放图像,或给音频叠加背景噪音
回到原视频 (00:03:30)

3.4 迁移学习

(p83)

迁移学习(transfer learning) 让你用其他任务的数据来帮你的任务——当你的应用数据很少时非常有用。

流程(以"手写数字 0–9 识别,但数据很少"为例):

  1. 先在一个大数据集(如 100 万张图、1000 个类别:猫/狗/车/人…)上训练一个神经网络;
  2. 保留前几层的参数(w^[1],b^[1],…,w^[4],b^[4]),换掉输出层(从 1000 个输出改为 10 个输出),只随机初始化新输出层的参数(w^[5],b^[5] 维度变了,必须重训);
  3. 在你的小数据集上继续训练:

  4. 选项一:冻结前面所有层(保持参数不变),只训练新的输出层——训练集非常小时更合适;

  5. 选项二:所有参数都继续训练,但用上一步的值初始化——训练集稍大时更好。

两步叫法:

为什么有效? 检测"猫/狗/车/人"时,网络前几层学到的是边缘、角点、基本曲线/形状——这些是通用的低级图像特征,对识别手写数字同样有用。

两个要点:

  1. 输入类型 x 必须相同:图像任务的预训练必须在图像上做;音频任务要在音频上预训练;文本任务在文本上预训练;
  2. 你通常不必自己预训练——很多人已经把预训练好的模型免费发布在网上(如 BERT、GPT、ImageNet 预训练模型),你可以直接下载、换输出层、微调。有了好的预训练模型,有时只用 50 张图微调就能得到不错的效果。

这也是机器学习社区共享成果的方式:别人花几周训练的模型,你直接下载微调即可。吴恩达希望你也回馈社区。

编者拓展|迁移学习为什么「讲得通」:深度学习的一个核心发现是:网络浅层学到的特征往往是通用的(边缘、角点、纹理),深层才逐步特化到具体任务。所以你可以把在大数据上预训练好的「通用特征提取器」搬过来,只重新训练「特化」的顶层(或做少量微调)。今天几乎所有大模型(BERT、GPT、CLIP……)的用法都建立在这个基础上——预训练 + 微调已经成了标准范式。

迁移学习:在大型数据集上监督预训练,再在自己的小数据上微调

📷 迁移学习:在大型数据集上监督预训练,再在自己的小数据上微调
回到原视频 (00:02:14)

3.5 机器学习项目的完整周期

(p84)

一个完整的 ML 项目包含这些阶段:

  1. 确定项目范围(scoping):决定做什么(如"语音搜索:用说话而不是打字做网页搜索");
  2. 收集数据:决定需要什么数据并去获取(音频 + 转录标签);
  3. 训练模型:训练 → 偏差/方差分析 → 误差分析 → 迭代改进;
  4. (根据分析)回去收集更多数据——可以是所有数据,也可以是特定类型的数据;
  5. 部署到生产:让用户能用;
  6. 监控与维护:持续监控性能,性能下降时回炉重训。

例(语音识别):吴恩达发现模型在背景有车噪时表现特别差,于是用数据增强获取更多"像在车里说话"的语音数据来提升性能——这就是"分析 → 补数据 → 再训练"的循环。

部署的常见形态:

为什么要监控? 因为数据会漂移。例如:

MLOps(机器学习运维) 指系统化地构建、部署、维护 ML 系统的实践:保证模型可靠、可扩展、有良好的日志与监控,并能适时更新。对服务数百万用户的系统,还常需高度优化的实现以控制计算成本。

部署:移动应用通过 API 调用推理服务器,并记录数据用于监控

📷 部署:移动应用通过 API 调用推理服务器,并记录数据用于监控
回到原视频 (00:03:55)

3.6 公平、偏见与伦理

(p85)

ML 算法正在影响数十亿人,所以构建影响人的系统时,必须认真考虑公平性、偏见与伦理。历史上已有多起完全不可接受的案例:

不当/有害的用途:

原则:技术本身是中性的,但使用技术的人要负责。构建影响人的系统时,务必让系统相对公平、尽量少偏见、符合伦理,只做你真正相信能让社会变得更好的事。

公平与伦理:ML 影响数十亿人,偏见与不当使用是真实风险

📷 公平与伦理:ML 影响数十亿人,偏见与不当使用是真实风险
回到原视频 (00:02:12)


第四章 倾斜数据集与精确率/召回率

(对应模块 14,视频 p86–p87)

4.1 倾斜数据集:准确率会骗人

(p86)

当正负样本比例严重失衡(远非 50:50)时,准确率/错误率不再是好指标。

例:用实验室数据检测一种罕见病(y=1 表示患病)。若只有 0.5% 的人患病,那么一个永远输出 y=0 的"笨算法"就有 99.5% 的准确率(0.5% 错误率)——它甚至"优于"你那个 1% 错误率的学习算法,但它一个病人都诊断不出来,毫无用处。

所以:如果错误率 1%、另一个 0.5%、另一个 1.2%,你很难判断哪个算法最好——因为错误率最低的那个可能完全没用。

改用精确率(precision)和召回率(recall)。为此先构建混淆矩阵(confusion matrix)(以实际类别为列、预测类别为行):

实际 1 实际 0
预测 1 真正例 TP 假正例 FP
预测 0 假负例 FN 真负例 TN

例(交叉验证集 100 个样本:25 个实际为正、75 个实际为负):

混淆矩阵:真正例/假正例/假负例/真负例

📷 混淆矩阵:真正例/假正例/假负例/真负例
回到原视频 (00:03:33)

4.2 精确率与召回率

(p86)

$$\text{Precision} = \frac{TP}{TP + FP}, \qquad \text{Recall} = \frac{TP}{TP + FN}$$

精确率=所有"预测为正"的样本中实际为正的比例;召回率=所有"实际为正"的样本中被正确检出的比例。

代入例子:

为什么这两个指标好:

精确率:预测为正的样本里有多少真的为正

📷 精确率:预测为正的样本里有多少真的为正
回到原视频 (00:07:28)

召回率:实际为正的样本里被找出了多少

📷 召回率:实际为正的样本里被找出了多少
回到原视频 (00:08:43)

4.3 精确率与召回率的权衡

(p87)

逻辑回归输出概率,我们通常按 0.5 阈值判正负。改变阈值就在两者间权衡:

提高阈值(如 0.7、0.9,"非常有信心才判正"):

降低阈值(如 0.3,"不确定就判正,安全第一"):

更一般地:把不同阈值下的精确率/召回率画成曲线,你就能手动挑一个点——平衡"假正例的代价"与"假负例的代价"。

注意:这个"选最佳点"通常没法用交叉验证自动完成——因为"哪个权衡更好"取决于你的业务判断,需要你来指定。

提高/降低阈值在精确率与召回率之间的权衡曲线

📷 提高/降低阈值在精确率与召回率之间的权衡曲线
回到原视频 (00:05:47)

4.4 用 F1 分数自动折中

(p87)

若要在多个算法间自动选一个,就需要把 P、R 合成一个数字。

不要用算术平均! 例如"总是判正"的算法召回率完美(1.0)、精确率极低,算术平均却可能不低,看起来"不错"——但它其实是个没用的算法。

正确做法是 F1 分数:

$$F_1 = \frac{2}{\frac{1}{P} + \frac{1}{R}} = \frac{2PR}{P + R}$$

例(三个算法):

算法 精确率 P 召回率 R 算术平均 F1
1 0.5 0.4 0.45 0.444
2 0.1 1.0 0.55 0.175
3 0.02 1.0 0.51 0.039

算法 3 的召回率完美(因为它几乎对所有人都判正),但精确率极低 → F1 只有 0.039。F1 告诉我们:算法 1 最好。

F1 分数 = P 与 R 的调和平均,更看重较小的值

📷 F1 分数 = P 与 R 的调和平均,更看重较小的值
回到原视频 (00:09:00)


第五章 决策树

(对应模块 15,视频 p88–p89)

5.1 决策树模型:以"猫分类器"为例

(p88)

决策树(decision tree) 是非常强大、被广泛使用的学习算法,也是很多机器学习竞赛的夺冠利器。虽然学术界对它的关注不如神经网络,但它非常值得放进你的工具箱。

例子:开一家猫咪收养中心,想根据三个特征快速判断一只动物是不是猫:

10 个训练样本(5 只猫 5 只狗),特征都是离散/分类值(只取几个离散值),标签 y 是 1/0(二元分类)。

决策树模型长成一棵树(计算机科学里的树是"根在顶部、叶子在底部"——可以类比成室内悬挂植物):

一个具体例子:一只尖耳、圆脸、有胡须的猫 → 从根节点看耳朵(尖)→ 向左走 → 看脸形(圆)→ 向下走 → 到达叶节点,预测"是猫"。

也可以用一句玩笑话记住:机器学习工程师在哪露营?——在"随机森林"里。

决策树:从根节点按特征一路判断,到叶节点得到预测

📷 决策树:从根节点按特征一路判断,到叶节点得到预测
回到原视频 (00:03:07)

同一个问题可以构造出很多不同的决策树(换特征、换分裂顺序),有些更好、有些更差。例如:

决策树学习算法的任务就是:从所有可能的树中,选出一棵在训练集上表现好、并能很好泛化到新数据(交叉验证集/测试集)的树。

5.2 学习过程

(p89)

构建决策树的核心是递归地选择"在哪个特征上分裂"。以 10 个样本为例:

  1. 选根节点的特征:用某个算法(下章讲)算出各特征的"信息增益",假设选耳朵形状——按它把 10 个样本分成左右两组(5 个尖耳 → 左,5 个垂耳 → 右);
  2. 只看左分支(5 个样本):再用算法选一个特征,假设选脸形——分成"圆脸 4 个"和"非圆脸 1 个";
  3. 左边这 4 个全是猫 → 创建叶节点、预测"是猫";那个非圆脸的不是猫 → 叶节点预测"非猫";
  4. 再看右分支(5 个样本,1 猫 4 狗):选特征(假设胡须)继续分。分出的左边 1 个是猫、右边 4 个不是猫——每个节点都"纯净"了,于是创建叶节点。

过程中有两个关键决策:

(1) 每个节点选哪个特征分裂? 目标是最大化纯度(purity)——让分出的子集尽可能"全是猫"或"全不是猫"。

如果有"该动物是否有猫的 DNA"这种特征,分出来左右都 100% 纯,就完美;但现实中只能用现有特征。

(2) 什么时候停止分裂? 几种标准:

为什么要限制树的生长? 因为树太大会过拟合——就像高阶多项式或超大神经网络一样。限制深度、最小增益、最小样本数,都能保持树较小、降低过拟合风险。理论上最大深度可用交叉验证选,但实践中开源库往往有更好的默认选择。

吴恩达也承认:决策树算法"看起来有点复杂和杂乱",因为它由很多研究者逐年改进叠加而成(有人提出基本版、有人加新的分裂标准、有人加停止标准……)。但这不影响它效果非常好——本课重点是如何用好它(后面会给出用开源库的实用建议)。

决策树递归构建:每个节点先看是否满足停止条件,否则选最优特征分裂

📷 决策树递归构建:每个节点先看是否满足停止条件,否则选最优特征分裂
回到原视频 (00:02:33)


第六章 决策树学习算法

(对应模块 16,视频 p90–p95)

6.1 测量纯度:熵

(p90)

如何量化一组样本的"纯度"?用熵(entropy)——它衡量不纯度。

设 p₁ 是"是猫(y=1)"样本的比例,p₀ = 1 − p₁ 是"不是猫"的比例。熵函数:

$$H(p_1) = -p_1\log_2(p_1) - p_0\log_2(p_0)$$

(取以 2 为底的对数,是为了让曲线峰值恰好为 1。)

性质:

几个例子(6 个样本):

样本构成 p₁ 熵 H(p₁) 含义
3 猫 3 狗 0.5 1.00 最不纯
5 猫 1 狗 5/6 ≈ 0.83 ≈ 0.65 较纯
6 猫 0 狗 1.0 0 完全纯
2 猫 4 狗 1/3 ≈ 0.33 ≈ 0.92 很不纯(更接近 50-50)
0 猫 6 狗 0 0 完全纯

计算约定:0·log(0) 在技术上未定义,但为计算熵,约定 0·log(0) = 0——这样在 p₁=0 或 1 处熵正好为 0。

编者拓展|「熵」从哪来:熵的概念来自 Shannon 1948 年的信息论。$H(X)=-\sum p_i\log_2 p_i$ 度量的是一个随机变量的平均不确定性(单位是 bit):取值越均匀、越难猜,熵越大;越确定,熵越小。决策树用「信息增益 = 分裂前后熵的减少」来挑特征,本质就是用一次提问换取尽可能多的信息——这也解释了为什么它和「20 个问题」游戏是同一个直觉。

你也可以用 Gini 准则(Gini index)——形状与熵类似、同样适合构建决策树。本课用熵。

熵函数:p₁=0.5 时最大(1),全纯时为 0

📷 熵函数:p₁=0.5 时最大(1),全纯时为 0
回到原视频 (00:01:11)

6.2 选择分裂特征:信息增益

(p91)

信息增益(information gain)= 熵的减少量。

以根节点为例(10 个样本,5 猫 5 狗,根节点熵 H(0.5) = 1)。对每个候选特征,计算分裂后的加权平均熵:

$$\text{加权平均熵} = w_{\text{左}}\,H(p_{1,\text{左}}) + w_{\text{右}}\,H(p_{1,\text{右}})$$

其中 w_左、w_右 是分到左/右分支的样本比例。

为什么要加权(而不是简单平均)? 因为节点里样本越多,它的熵是否低就越重要——"一个有很多样本、且很不纯的节点"比"一个只有少量样本、很不纯的节点"更糟。

三个候选特征的计算(根节点,10 个样本):

特征 左分支 右分支 加权平均熵
耳朵形状 5 个,p₁=0.8 5 个,p₁=0.2 0.5·H(0.8)+0.5·H(0.2) ≈ 0.72
脸形 7 个,p₁=4/7 3 个,p₁=1/3 0.7·H(4/7)+0.3·H(1/3) ≈ 0.97
胡须 4 个,p₁=0.75 6 个,p₁=2/6 0.4·H(0.75)+0.6·H(2/6) ≈ 0.88

信息增益定义为:

$$\text{信息增益} = H(p_{1,\text{根}}) - \big[w_{\text{左}}H(p_{1,\text{左}}) + w_{\text{右}}H(p_{1,\text{右}})\big]$$

于是:

选信息增益最大的特征(耳朵形状)。

为什么用"信息增益"而不是直接比较加权熵? 因为"信息增益太小就停止分裂"是一个现成的停止标准——gain 低于阈值时不再分裂,避免树无谓变大、过拟合。这是一个额外的实用功能。

通用公式(以"耳朵形状"为例):设

则

$$\text{Information Gain} = H(p_{1,\text{根}}) - \big[w_{\text{左}}H(p_{1,\text{左}}) + w_{\text{右}}H(p_{1,\text{右}})\big]$$

从所有候选分裂里,选信息增益最高的特征。

信息增益:根节点熵 减去 左右分支加权熵,选增益最大的特征

📷 信息增益:根节点熵 减去 左右分支加权熵,选增益最大的特征
回到原视频 (00:10:18)

6.3 整合成完整算法

(p92)

决策树构建过程:

  1. 从根节点开始(含全部训练样本),计算所有特征的信息增益,选增益最大的特征分裂;
  2. 按该特征把数据分成左右两个子集,建立左/右分支;
  3. 对左、右分支递归地重复;
  4. 直到满足停止标准(节点纯、达到最大深度、增益小于阈值、样本数小于阈值)。

关键洞察:构建根节点之后,构建左子树 = 用左手边那批样本"重新训练一棵(更小的)决策树",右子树同理。这就是一个递归算法——"用更小的子树拼出整棵树"。看决策树的软件实现时,常会看到"递归算法"的说法。(不亲自实现的话,不理解递归也完全能完成作业。)

可视化过程:遮住根节点和右分支,只看左分支那 5 个样本——把它当成一个小数据集,重新算各特征的信息增益(注意此时"耳朵形状"的增益为 0,因为这 5 个都是尖耳),选最优特征继续分,直到满足停止标准;再回过头构建右子树。

递归构建:先定根节点分裂,再对左右子集分别

📷 递归构建:先定根节点分裂,再对左右子集分别"再建一棵树"
回到原视频 (00:01:16)

6.4 处理多值特征:独热编码

(p93)

之前每个特征只有两个取值。若"耳朵形状"有三种取值(尖耳 / 垂耳 / 椭圆耳),可以有两种处理:

一般地,一个 k 值的分类特征可以拆成 k 个 0/1 特征。这样又回到"每个特征只取两个值"的设定,之前的学习算法无需修改即可使用。

独热编码不只用于决策树:神经网络、逻辑回归、线性回归都要求输入是数字,所以也可以用独热编码把分类特征编码成 0/1 输入。例如把"脸形:圆/非圆"、胡须"有/无"、耳朵"尖/垂/椭圆"编码成一组 0/1 特征,送入神经网络训练猫分类器。

独热编码:把 3 值的

📷 独热编码:把 3 值的"耳朵形状"拆成 3 个 0/1 特征
回到原视频 (00:02:32)

6.5 处理连续值特征

(p94)

若特征取任意数值(如动物体重),决策树的做法是:按"是否 ≤ 某个阈值"来分裂。

学习算法要选择最优阈值。做法:

  1. 把样本按该特征值排序;
  2. 取相邻值的中点作为候选阈值(m 个样本 → m−1 个候选);
  3. 对每个候选做常规的信息增益计算;
  4. 若该连续特征的最大信息增益优于所有其他特征(含其他连续特征的各阈值),就在该特征的这个阈值上分裂。

例(体重特征):尝试"≤8"→ 增益 0.24;"≤9"→ 增益 0.61;"≤13"→ 增益 0.40。0.61 最高且高于其他特征,于是按"体重 ≤ 9"分裂。

连续特征:按

📷 连续特征:按"体重 ≤ 阈值"分裂,选信息增益最大的阈值
回到原视频 (00:03:12)

6.6 回归树(可选)

(p95)

决策树也能做回归(预测数值,如预测动物体重):回归树(regression tree)。

$$\text{方差减少量} = \operatorname{Var}(\text{全部样本}) - \big[w_{\text{左}}\operatorname{Var}_{\text{左}} + w_{\text{右}}\operatorname{Var}_{\text{右}}\big]$$

例(γ 无关,纯方差):全部 10 个样本方差 20.51;按耳朵形状分裂后方差减少 8.84、按脸形 0.64、按胡须 6.22 → 选耳朵形状。

结果:同一个决策树框架,既能做分类,也能做回归。

回归树:叶节点预测 y 的均值,按

📷 回归树:叶节点预测 y 的均值,按"方差减少最多"选分裂特征
回到原视频 (00:04:31)


第七章 集成学习:随机森林与 XGBoost

(对应模块 17,视频 p96–p100)

7.1 单棵树的问题:太敏感

(p96)

单个决策树对数据的微小变化高度敏感。 例:只把 10 个训练样本中的一个换成另一只猫(原为"尖耳、圆脸、无胡须",新为"垂耳、圆脸、有胡须"),根节点选的最佳特征就可能从"耳朵形状"变成"胡须"——于是左右子树的数据子集完全不同,整棵树也完全不同。

解决办法:不建一棵树,而是建一大"堆"树——树集成(tree ensemble)。

预测时让所有树投票:例如三棵树里两棵说"是猫",最终就预测"是猫"。这样任何单棵树的影响都被稀释(三票里只占一票),整体算法更稳健。

树集成:多棵树各投票,整体对单棵树的变化不敏感

📷 树集成:多棵树各投票,整体对单棵树的变化不敏感
回到原视频 (00:02:50)

7.2 有放回抽样

(p97)

构建树集成需要有放回抽样(sampling with replacement):

这个新集合有些样本重复、有些样本没被抽到——因此与原始集相似但有差异。(举例:从 4 个彩色标记里摸 4 次,可能得到"绿、黄、蓝、蓝"——重复了蓝色、没抽到红色。)这种"相似但不同"的新训练集,正是构建树集成的关键积木。

有放回抽样:抽一个、放回、再抽,得到相似但有差异的新训练集

📷 有放回抽样:抽一个、放回、再抽,得到相似但有差异的新训练集
回到原视频 (00:01:25)

7.3 随机森林

(p98)

袋装决策树(bagged decision tree):

for b = 1 to B:
    用有放回抽样生成一个大小为 m 的新训练集
    在新训练集上训练一棵决策树
预测时:让 B 棵树投票决定最终预测

随机森林(random forest)是对袋装决策树的改进:

问题:即使有放回抽样,很多数据集里各棵树的根节点附近仍然选择相同的特征,导致树太相似。

做法:在每个节点分裂时,只从随机抽取的 k 个特征中选最优(而不是用全部 n 个特征):

if n 个特征可用:
    随机选 k 个特征作为"允许的特征"(k < n)
    只从这 k 个特征里选信息增益最高的来分裂

为什么更稳健? 有放回抽样让算法探索了数据的多种小变化,并把它们平均起来;因此训练集的任何进一步小改动都不太可能对整体输出造成大影响。

编者拓展|随机森林与 Leo Breiman:随机森林由统计学家 Leo Breiman 于 2001 年提出,它把两件事结合起来——Bagging(bootstrap aggregating,有放回抽样 + 投票,Breiman 1996)与随机特征子集(Amit & Geman 1997 的思想)。直觉是:把许多「高方差、低偏差」的树平均起来,方差被抵消,得到一个又稳又准的模型。它至今仍是表格数据上最强的基线之一。

(再次记住那句玩笑:机器学习工程师在哪露营?——在随机森林里。)

随机森林:有放回抽样造多份数据;每个节点再从随机特征子集中选分裂特征

📷 随机森林:有放回抽样造多份数据;每个节点再从随机特征子集中选分裂特征
回到原视频 (00:01:46)

7.4 XGBoost:提升决策树

(p99)

提升(boosting)的思想:每一轮更关注"上一轮仍分错的样本"。

类比——刻意练习:练钢琴不是每次从头弹整首曲子(很耗时),而是专攻还没掌握的那几小节——这才是更高效的练习方式。提升就是让每一棵新树专注在当前集成仍处理不好的样本上。

流程:

  1. 训练第一棵树后,回到原始训练集,看它对每个样本的预测,标记哪些错了;
  2. 第二次有放回抽样时,给"仍然分错"的样本更高的被选中概率("关注"这些样本);
  3. 如此迭代 B 次,第 b 轮时更可能抽到"前 b−1 棵树集成仍分错"的样本;
  4. 最终让这些树的集成协同处理难题。

("给样本加权"的数学细节较复杂,但用实现时不需要关心。)

XGBoost(Extreme Gradient Boosting) 是目前最常用的提升树实现:

编者拓展|「提升」与「梯度提升」的关系:Boosting 的思想是「串行地、每一步修正前一步的错误」——和 Bagging(并行训练、投票)正好相反。把「每一步都沿损失函数的负梯度方向」这一思想形式化,就得到 梯度提升(Gradient Boosting, Friedman 2001);XGBoost 是它的高效工程实现(正则化目标、二阶信息、列采样、稀疏感知、系统级优化)。它的作者 陈天奇 是华人研究者,这也让 XGBoost 成为在 Kaggle 上最常被引用的算法之一。

import xgboost as xgb
model = xgb.XGBClassifier()          # 分类;回归用 xgb.XGBRegressor()
model.fit(X, Y)
yhat = model.predict(X_new)
XGBoost:每次新树都更关注

📷 XGBoost:每次新树都更关注"当前集成仍分错"的样本
回到原视频 (00:04:57)

7.5 决策树 vs 神经网络:怎么选

(p100)

两者都是非常强大、非常有效的算法。选择时可参考:

决策树 / 树集成 神经网络
表格/结构化数据 ✅ 很擅长 ✅ 也很有竞争力
非结构化数据(图像/视频/音频/文本) ❌ 不推荐 ✅ 首选
混合数据(结构化 + 非结构化) —— ✅ 也表现良好
训练速度 ✅ 非常快(利于快速迭代) ❌ 可能很慢
可解释性 小树可解释(几十个节点可打印出来看);但集成后很难(100 棵树 × 数百节点) 较差
迁移学习 ❌ 不支持 ✅ 支持(小数据集时很关键)
串联多个模型 只能一次训一棵 ✅ 输出是可微的平滑函数,可用梯度下降同时训练多个串联网络

实用建议:

决策树/集成 vs 神经网络:按数据类型、训练速度、可解释性、迁移学习来选

📷 决策树/集成 vs 神经网络:按数据类型、训练速度、可解释性、迁移学习来选
回到原视频 (00:01:15)


自测与思考题(进阶)

  1. 诊断:$J_{train}=1\%$、$J_{cv}=11\%$,更像高偏差还是高方差?下一步优先做什么?反过来 $J_{train}=15\%$、$J_{cv}=16\%$ 呢?
  2. 参数变化:增大正则化 $\lambda$ 时,$\lVert w\rVert$、偏差、方差各如何变化?为什么?
  3. 取舍:精确率与召回率在什么业务下应更看重召回率?(举一个例子。)
  4. 理解:随机森林为什么比单棵决策树更稳?用「有放回抽样」解释。
  5. 反例:判断对错并说明理由——「$J_{train}$ 很低就说明模型很好」。

参考答案要点

  1. 前者更像高方差(过拟合):优先加数据 / 加正则 / 简化模型;后者更像高偏差(欠拟合):优先改用更强的模型(更多特征/更多层)。
  2. $\lambda\uparrow\Rightarrow\lVert w\rVert\downarrow$;偏差 ↑;方差 ↓。原因是参数被收缩(约束变强),模型更不灵活、对噪声不敏感。
  3. 漏检代价高的场景,如疾病筛查 / 垃圾邮件倾向——宁可误报也要尽量不漏(召回率高)。
  4. 每棵树在不同 bootstrap 子集上训练、并随机选特征分裂,各自的方差被平均,因此整体更稳、泛化更好。
  5. 错。低 $J_{train}$ 只说明拟合了训练集;可能是过拟合,要看 $J_{cv}$ 与泛化差距。

结语

恭喜你完成机器学习实践与决策树这一册!本册讲的不是"某个新模型",而是如何把模型真正用好,以及另一类强大的算法:

有了"神经网络"与"实践方法 + 决策树"这两块,你已经具备构建多种机器学习应用的能力。


附:来源与参考

版权说明:课程视频、字幕与讲义版权归 DeepLearning.AI / Stanford 所有。本电子书为个人学习所做的中文书面重构,未获授权,不得用于任何商业用途或公开传播。书中截图取自对应分P视频画面,并标注「分P @ 时间」以便回源核对。