共计 1341 个字符,预计需要花费 4 分钟才能阅读完成。
为什么需要后剪枝?
刚接触决策树时,我总发现训练集准确率接近 100%,但测试集表现糟糕——这就是典型的过拟合。后剪枝(Post-Pruning)就像给树做 ” 整形手术 ”,通过修剪不必要的分支来提高泛化能力。与预剪枝(Pre-Pruning)不同,后剪枝允许树先充分生长,再反向修剪,避免了预剪枝可能导致的欠拟合问题。

核心数学原理
决策树分裂时使用基尼系数(Gini Index)衡量不纯度:
Gini(t) = 1 - Σ[p(i|t)^2]
后剪枝通过代价复杂度(Cost-Complexity Pruning)平衡误差与复杂度:
Rα(T) = R(T) + α|T|
其中:
– R(T)是误分类率
– |T| 是叶节点数
– α 是调节参数(越大剪枝越激进)
过拟合可视化诊断
用 sklearn 生成一个深度为 10 的未剪枝树:
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt
plt.figure(figsize=(20,10))
plot_tree(clf_unpruned, filled=True, feature_names=X.columns)
plt.show()
你会发现树结构复杂,存在大量只覆盖单个样本的节点——这些就是需要修剪的 ” 过拟合分支 ”。
代价复杂度剪枝四步法
1. 计算 CCP 路径
path = clf.cost_complexity_pruning_path(X_train, y_train)
ccp_alphas = path.ccp_alphas
2. 交叉验证选择 α
from sklearn.model_selection import cross_val_score
alpha_scores = []
for alpha in ccp_alphas:
temp_clf = DecisionTreeClassifier(ccp_alpha=alpha)
scores = cross_val_score(temp_clf, X_train, y_train, cv=5)
alpha_scores.append(np.mean(scores))
3. 选择最佳 α 值
optimal_alpha = ccp_alphas[np.argmax(alpha_scores)]
4. 训练最终模型
clf_pruned = DecisionTreeClassifier(ccp_alpha=optimal_alpha)
clf_pruned.fit(X_train, y_train)
避坑实践指南
- 数据泄露陷阱:绝对不要用测试集选择 α!必须严格区分训练 / 验证 / 测试集
- 特征缩放影响:决策树虽不要求归一化,但高基数特征会获得不合理的高重要性
- 随机性控制 :设置
random_state保证实验可复现,尤其是在交叉验证时
效果对比实验
| 指标 | 未剪枝树 | 剪枝后树 |
|---|---|---|
| 训练集 F1 | 0.99 | 0.93 |
| 测试集 F1 | 0.82 | 0.88 |
| 预测时延(ms) | 3.2 | 1.7 |
从我的信用卡欺诈检测项目看,剪枝后模型:
– 测试集 F1 提升 6%
– 推理速度加快 47%
– 模型体积缩小 80%
最佳实践建议
- 先用
max_depth=3快速建立基线模型 - 逐步放松限制让树生长
- 最后用后剪枝优化
- 商业场景建议 α≤0.02(保持可解释性)
完整代码已上传 Github(含 Jupyter 可视化示例),欢迎 Star 交流!
正文完
