← 返回题目列表

决策树的剪枝是什么?预剪枝和后剪枝有什么区别?

高频 中等 第 6 / 25 题 更新于 2026/09/25
决策树剪枝预剪枝后剪枝过拟合
学习 AI 实战项目

简化版

剪枝通过限制或删除分支控制树的容量,目标是改善验证泛化而不是保证“越小越好”。预剪枝在生长中以深度、叶样本数、最小增益等条件拒绝切分,计算省但可能过早阻断后续有价值结构;后剪枝先生成一棵较大的候选树,再自底向上比较子树与叶子。REP 使用独立验证集,C4.5 的悲观剪枝使用训练误差校正,CART 的代价复杂度剪枝生成嵌套子树并通常用交叉验证选 α,所以后剪枝不都等于“看一个验证集”。

详细版

为什么要剪枝: 决策树不加限制会一直分到每个叶子极纯,把训练集(含噪声)完全记住 → 过拟合、高方差,测试表现差。

预剪枝 vs 后剪枝:

预剪枝后剪枝
时机建树时提前停止建完整棵树后再剪
方向自顶向下(边建边停)自底向上(从叶子往上剪)
速度快(树小,省算力)慢(先建满再剪)
欠/过拟合可能欠拟合(过早停止)搜索候选更充分,但泛化不保证更好
代表方法max_depth、min_samples_leaf、min_impurity_decrease悲观剪枝(C4.5)、代价复杂度剪枝(CART/CCP)

预剪枝常用停止条件:

  • 树深度达上限、节点样本数低于阈值、叶子样本数低于阈值、纯度提升小于阈值、划分后验证集精度不升。

后剪枝方法:

  • REP(错误率降低剪枝):用验证集,剪掉后错误率不上升就剪。
  • 悲观剪枝(PEP,C4.5):用训练集加惩罚估计,无需单独验证集。
  • 代价复杂度剪枝(CCP,CART):最小化 误差 + α×叶子数,用交叉验证选 α。

完整版教学

一、为什么决策树非剪不可

决策树如果不加任何限制,会一直分裂到每个叶子都极纯(甚至每个叶子只有一个样本)。这样的树把训练集的每个细节、包括噪声都记了下来——训练误差几乎为 0,但这是「背答案」,换到测试集就崩。这就是决策树天生容易过拟合、高方差的根源。

剪枝就是主动砍掉一些对泛化没帮助(甚至有害)的分支,让树变浅变简单,用一点训练精度换取更好的泛化。它是决策树对抗过拟合的头号武器(另一个是集成)。按剪枝发生的时机,分预剪枝和后剪枝。

二、预剪枝:边建树边喊停

预剪枝在建树过程中就设置条件,一旦满足就停止继续分裂,把当前节点直接变成叶子。常用停止条件(也就是 sklearn 里那些超参数):

  • max_depth:树的最大深度,到了就不再分。
  • min_samples_split:节点样本数少于它就不再分裂。
  • min_samples_leaf:分裂后若某叶子样本数太少,就不允许这次分裂。
  • min_impurity_decrease:分裂带来的纯度提升小于阈值就不分(提升太小不值得)。
  • 验证集准则:若这次分裂不能提升验证集精度,就不分。

优点:树在生长时就被控制得较小,训练快、省内存、模型简单。

致命缺点——可能欠拟合:预剪枝是贪心地看「眼前」。有时某次分裂当前看提升不大(甚至没提升),但它之后能带来非常有用的深层分裂——预剪枝会因为「眼前提升不够」而提前停止,错过后面的好分裂。这种「目光短浅」导致预剪枝有欠拟合风险。

三、后剪枝:先长满,再往回砍

后剪枝反过来:先让决策树完全生长(尽情过拟合),然后自底向上逐个考察内部节点——尝试把某个子树整体替换成一个叶子节点(叶子类别取该子树样本中最多的类),如果替换后泛化能力不下降(甚至提升),就执行这次剪枝。

优点:后剪枝基于较大的候选树比较整棵子树的误差与复杂度,能降低预剪枝因局部早停而错过后续结构的风险。它通常需要更多训练与存储成本,泛化效果是否优于预剪枝仍要通过同一验证方案比较。

缺点:要先建完整棵大树再剪,计算和内存开销更大、更慢。

经典 CART 用代价复杂度目标 R_α(T)=R(T)+α|T| 生成一串嵌套子树:α 越大,对叶节点数量的惩罚越强,得到的树越小。训练误差必然偏爱更大的树,所以最终 α 应通过交叉验证选择;测试集只能用于最终一次评估,不能参与剪枝强度选择。

四、后剪枝的三种经典方法

1. REP(错误率降低剪枝,Reduced Error Pruning)

用独立的验证集:自底向上,对每个内部节点,比较「保留子树」和「剪成叶子」在验证集上的错误率,剪掉后错误率不升就剪。简单直接,但需要额外划出验证集(数据少时是负担)。

2. 悲观剪枝(PEP,C4.5 采用)

不需要单独验证集,只用训练集估计。它给训练误差加一个惩罚项(因为训练误差过于乐观),用这个「悲观」的误差估计来判断是否剪枝。好处是不浪费数据划验证集,速度快;是 C4.5 的默认方式。

3. 代价复杂度剪枝(CCP,CART 采用)

CART 的后剪枝,核心是在「误差」和「树的复杂度」之间权衡,最小化:

代价复杂度 = 误差(T) + α × |叶子数(T)|
  • α 是复杂度惩罚系数:α 越大越倾向简单的树(叶子少)。
  • 做法:对不同 α 生成一系列剪枝后的子树,再用交叉验证选出泛化最好的那棵(对应最优 α)。
  • 这和正则化思想一致——误差 + α×复杂度,用 α 控制模型简单程度。sklearn 的 ccp_alpha 参数就是它。

五、预剪枝 vs 后剪枝怎么选

场景倾向
数据量大、算力紧张预剪枝(快、省资源)
希望从嵌套子树路径选复杂度后剪枝 + 独立验证
数据少可比较交叉验证 CCP 或 PEP,避免固定留出集过小

实践建议:

  • 单棵树可把 CCP 与交叉验证作为候选,也可直接联合调预剪枝参数;没有跨数据集“后剪枝通常必优”的结论。
  • 工程上也常用预剪枝超参数(max_depth、min_samples_leaf 等)+ 交叉验证调参来控制复杂度,简单有效。
  • 两者可结合:先预剪枝控制规模,再后剪枝精修。

六、常见追问

  • 剪枝和集成什么关系? 都是对付过拟合。单棵树靠剪枝;随机森林靠 Bagging 多树平均降方差,单棵树反而可以不剪、长满(靠集成消化方差);GBDT 用浅树 + 正则。
  • 预剪枝为什么会欠拟合? 贪心地提前停止,可能砍掉「当前提升小但后续有用」的分支。
  • CCP 里的 α 怎么定? 生成 α 序列对应的子树,用交叉验证选泛化最好的。
  • 不做后剪枝行不行? 可以使用深度、叶样本和最小增益等生长约束;Bagging 常允许较深基树,但仍可能设置叶样本、特征采样等约束,不能概括为完全不控复杂度。

七、用成本复杂度目标判断该不该砍

设子树有 5 个叶子,训练误差 0.10;把它替换成单叶后误差升到 0.14。成本复杂度目标 R(T)+α|T| 下,保留子树的目标是 0.10+5α,剪成单叶是 0.14+α;两者在 α=0.01 时相等。α 更大时复杂度代价占优,算法倾向剪枝。

R_alpha(T) = R(T) + alpha * |leaves(T)|
keep: 0.10 + 5*alpha
prune: 0.14 + 1*alpha
对象/方案核心机制选择或风险
预剪枝生长过程中触发深度/样本/增益门槛快,但可能错过后续有价值结构
后剪枝先得到大树,再比较子树替换搜索更充分,计算和验证成本更高
成本复杂度用 α 权衡经验误差与叶数产生一条嵌套子树路径供验证选择
生长大树 → 计算最弱环节 α → 依次剪出子树序列
                              → 交叉验证选 α → 重训/定稿

记忆钩子:剪枝选择的是泛化复杂度,不是追求节点越少越好;α 应由未参与拟合的数据决定。

八、常见误区与追问

  • 误区:预剪枝和后剪枝只是执行时间不同。 预剪枝可能提前阻断后续有用切分,搜索空间也不同。
  • 误区:后剪枝一定优于预剪枝。 数据量、算力和验证噪声都会影响结果,没有无条件保证。
  • 追问:ccp_alpha 越大树会怎样? 复杂度惩罚更强,通常得到叶子更少的子树路径。
  • 追问:能用测试集选择剪枝强度吗? 不能,应使用训练内交叉验证或验证集,测试集只做最终评估。
  • 追问:随机森林里的单树还要强剪枝吗? 通常允许较深树保留低偏差,再靠去相关平均降方差,但仍受叶样本等约束。

九、加强记忆

剪枝是控制决策树方差与复杂度的核心。预剪枝在建树时用 max_depth、min_samples_leaf、min_impurity_decrease 等提前停止,节省资源但可能错过后续结构;后剪枝从较大候选树自底向上简化,搜索更充分但不保证泛化一定更好。REP 使用验证集,C4.5 的 PEP 使用训练误差校正,CART 的 CCP 最小化 R(T)+α|leaves(T)| 并用交叉验证选 α。实践应在同一数据切分与指标下比较预剪枝、后剪枝或二者组合;随机森林的基树常较深,也仍需用叶样本、特征采样和验证表现控制整体方案。