SilverIce Toolbox
Back to course

Stage 2 / Chapter 9

第9章:决策树与集成学习 | Chapter 9: Decision Trees & Ensemble Learning

阶段定位 | Stage: 第二阶段 — 神经网络与进阶算法 预计学时 | Duration: 3~4 小时

---

学习目标 | Learning Objectives

中文:

  • 理解决策树的分裂标准:信息增益与 Gini 不纯度
  • 理解决策树过拟合的倾向及剪枝策略
  • 掌握 Bagging(随机森林)和 Boosting(XGBoost)的核心区别
  • 理解为什么随机森林能减少方差,XGBoost 能减少偏差
  • 能在表格数据上正确选择决策树或神经网络

English:

  • Understand decision tree splitting criteria: information gain and Gini impurity
  • Understand decision tree overfitting tendency and pruning strategies
  • Master the core differences between Bagging (Random Forest) and Boosting (XGBoost)
  • Understand why Random Forest reduces variance and XGBoost reduces bias
  • Correctly choose between decision trees and neural networks for tabular data

---

9.1 决策树 | Decision Trees

中文解释

核心思想

通过一系列如果-那么规则把数据分到不同区域:

如果 年龄 < 30 且 收入 > 5000:
    → 批准贷款
否则:
    → 拒绝贷款

分裂标准

标准公式特点
信息增益IG = H(parent) - Σ(p_i * H(child_i))基于熵,ID3/C4.5 使用
Gini 不纯度Gini = 1 - Σ(p_i²)计算更快,CART 使用

Gini 不纯度直觉

  • Gini = 0:节点内所有样本属于同一类(最纯)
  • Gini = 0.5:节点内两类各占 50%(最混乱)

决策树的优点

  • 可解释性极强(能画出树结构)
  • 无需特征缩放
  • 能处理类别特征和数值特征
  • 训练速度快

决策树的缺点

  • 极易过拟合:不加限制时,树可以生长到每个叶节点只有一个样本
  • 对数据波动敏感:换几个样本,树结构可能完全不同
  • 无法捕捉特征间的复杂交互(除非很深)

English Explanation

Splitting Criteria:

CriterionFormulaUsed By
Information GainH(parent) - Σp_i·H(child)ID3, C4.5
Gini Impurity1 - Σp_i²CART

Pros: interpretable, no scaling needed, fast training Cons: prone to overfitting, sensitive to data changes

---

9.2 随机森林 | Random Forest

中文解释

核心思想:Bagging + 随机特征

技术含义作用
BaggingBootstrap Aggregating:从训练集有放回抽样,训练多棵树减少方差
随机特征每棵树每次分裂时,只考虑随机子集的特征增加树之间的多样性

为什么能降低方差?

单棵决策树是高方差模型(对训练数据敏感)。多棵树取平均:

Var(average of n trees) = Var(single tree) / n   (假设树之间独立)

虽然树之间不是完全独立的(共享部分数据),但随机特征子集让它们足够不同,平均后仍显著降低方差。

关键超参数

参数含义调参建议
n_estimators树的数量越多越好(边际收益递减),通常 100~500
max_depth最大深度限制过拟合,默认 None(不限制)
max_features每分裂考虑的特征数"sqrt"(分类)或 "log2"
min_samples_leaf叶节点最少样本数增大可减少过拟合

English Explanation

Why Random Forest reduces variance:

Var(average of n trees) ≈ Var(single tree) / n

Random feature subsets ensure trees are diverse enough for this averaging to work.

---

9.3 XGBoost | Extreme Gradient Boosting

中文解释

核心思想:Boosting

与 Bagging 的"并行训练多棵树然后投票"不同,Boosting 是串行训练

  1. 训练第一棵树,得到预测 F₁(x)
  2. 计算残差(真实值 - 预测):r₁ = y - F₁(x)
  3. 训练第二棵树去拟合残差:F₂(x) ≈ r₁
  4. 更新预测:F(x) = F₁(x) + η·F₂(x) (η 是学习率)
  5. 重复直到 N 棵树

为什么能降低偏差?

每一棵新树都在纠正前面所有树的错误。随着树越来越多,模型能力越来越强,偏差越来越低。

XGBoost 的改进

改进点效果
二阶泰勒展开用梯度和 Hessian 同时优化,收敛更快
正则化项Ω = γT + ½λΣw²,控制树的复杂度
列抽样类似随机森林,防止过拟合
缺失值处理自动学习缺失值的最优分裂方向
并行化在特征层面并行,训练速度快

XGBoost vs 随机森林

特性随机森林XGBoost
策略Bagging(并行)Boosting(串行)
目标降低方差降低偏差
训练速度快(完全并行)较快(特征并行)
调参难度简单较复杂
表格数据效果很好通常更好
大数据极好(支持分布式)

English Explanation

Boosting vs Bagging:

  • Bagging: train trees in parallel, vote/average → reduces variance
  • Boosting: train trees sequentially, each corrects previous errors → reduces bias

XGBoost improvements: second-order Taylor expansion, regularization, column sampling, missing value handling, feature-level parallelism.

---

9.4 完整实现:决策树与集成学习

代码案例

python
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.ensemble import RandomForestClassifier
import matplotlib.pyplot as plt

np.random.seed(42)

# ========== 1. 生成数据 ==========
X, y = make_classification(n_samples=1000, n_features=4, n_redundant=0,
                           n_informative=4, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

feature_names = [f'F{i}' for i in range(4)]

# ========== 2. 单棵决策树 ==========
tree = DecisionTreeClassifier(max_depth=5, random_state=42)
tree.fit(X_train, y_train)
print(f"单棵决策树 (max_depth=5):")
print(f"  训练准确率: {tree.score(X_train, y_train):.4f}")
print(f"  测试准确率: {tree.score(X_test, y_test):.4f}")

# 不加限制时的过拟合
tree_unrestricted = DecisionTreeClassifier(random_state=42)
tree_unrestricted.fit(X_train, y_train)
print(f"\n不加限制的决策树:")
print(f"  训练准确率: {tree_unrestricted.score(X_train, y_train):.4f}")  # 可能 1.0
print(f"  测试准确率: {tree_unrestricted.score(X_test, y_test):.4f}")   # 可能下降

# ========== 3. 随机森林 ==========
rf = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)
rf.fit(X_train, y_train)
print(f"\n随机森林 (100 trees, max_depth=5):")
print(f"  训练准确率: {rf.score(X_train, y_train):.4f}")
print(f"  测试准确率: {rf.score(X_test, y_test):.4f}")

# 特征重要性
print(f"\n特征重要性:")
for name, imp in zip(feature_names, rf.feature_importances_):
    print(f"  {name}: {imp:.3f}")

# ========== 4. 可视化单棵树 ==========
fig, ax = plt.subplots(figsize=(16, 8))
plot_tree(tree, max_depth=3, fontsize=8, ax=ax, filled=True,
          feature_names=feature_names, class_names=['Class 0', 'Class 1'])
plt.title('Decision Tree Structure (depth=3 shown)')
plt.tight_layout()
plt.savefig('ch09_decision_tree.png')
print("\n树结构可视化已保存")

# ========== 5. 树数量与准确率的关系 ==========
n_trees_range = [1, 5, 10, 25, 50, 100, 200]
train_scores = []
test_scores = []

for n in n_trees_range:
    rf_n = RandomForestClassifier(n_estimators=n, max_depth=5, random_state=42)
    rf_n.fit(X_train, y_train)
    train_scores.append(rf_n.score(X_train, y_train))
    test_scores.append(rf_n.score(X_test, y_test))

plt.figure(figsize=(8, 5))
plt.plot(n_trees_range, train_scores, 'o-', label='Train Accuracy')
plt.plot(n_trees_range, test_scores, 's-', label='Test Accuracy')
plt.xlabel('Number of Trees')
plt.ylabel('Accuracy')
plt.title('Random Forest: Accuracy vs Number of Trees')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('ch09_rf_n_estimators.png')
print("随机森林树数量对比已保存")

典型输出:

单棵决策树 (max_depth=5):
  训练准确率: 0.9238
  测试准确率: 0.8900

不加限制的决策树:
  训练准确率: 1.0000
  测试准确率: 0.8550

随机森林 (100 trees, max_depth=5):
  训练准确率: 0.9287
  测试准确率: 0.9100

特征重要性:
  F0: 0.412
  F1: 0.234
  F2: 0.198
  F3: 0.156
不加限制的决策树训练准确率 100%(过拟合),测试准确率反而下降。随机森林通过平均降低了方差,测试准确率更高。

---

9.5 决策树 vs 神经网络:如何选择 | Trees vs Neural Nets

中文解释

表格数据(结构化数据)

场景推荐原因
特征 < 100,样本 < 10KXGBoost / LightGBM效果好、训练快、无需调参
特征中有大量类别变量XGBoost对类别特征处理更好
需要可解释性决策树 / 随机森林能输出规则、特征重要性
表格数据 + 海量样本XGBoost / TabNetXGBoost 支持分布式

非结构化数据

场景推荐原因
图像CNN(第16章起)空间结构需要卷积
文本 / 序列RNN / Transformer(第20章起)时序/语义依赖
音频CNN + RNN频谱特征 + 时序

混合数据

很多实际场景是混合的:用户画像(表格)+ 行为序列(文本)+ 头像(图像)。

  • 分别用适合的模型提取特征
  • 最后拼接用全连接层或 XGBoost 做最终预测

English Explanation

Tabular Data: XGBoost / LightGBM usually win Unstructured Data: Neural networks (CNN for images, Transformer for text) Mixed Data: Combine specialized models, then ensemble

---

本章总结 | Chapter Summary

中文:

  • 决策树通过 if-else 规则划分数据,Gini 不纯度衡量节点纯度
  • 单棵决策树极易过拟合,需要限制深度或剪枝
  • 随机森林 = Bagging + 随机特征,通过平均多棵树降低方差
  • XGBoost = Boosting + 正则化,通过串行纠错降低偏差
  • 表格数据上,XGBoost/LightGBM 通常优于神经网络
  • 非结构化数据上,神经网络是必选
  • 混合场景:各取所长,最后融合

English:

  • Decision trees split data via if-else rules; Gini measures node purity
  • Single trees overfit easily; need depth limits or pruning
  • Random Forest = Bagging + random features, reduces variance by averaging
  • XGBoost = Boosting + regularization, reduces bias by sequential correction
  • For tabular data, XGBoost/LightGBM usually outperform neural nets
  • For unstructured data, neural networks are essential
  • Mixed scenarios: combine specialized models

---

课后练习 | Homework

  1. Gini 计算:一个节点有 100 个样本,其中 70 个类别 A,30 个类别 B。计算 Gini 不纯度。如果分裂后左子节点 40A+10B,右子节点 30A+20B,计算信息增益。
  1. 过拟合控制:在同一数据上,分别训练 max_depth=[1, 3, 5, 10, None] 的决策树。画出训练/测试准确率随深度的变化曲线。
  1. Bagging vs Boosting:用相同数据分别训练随机森林和 XGBoost(或 GradientBoosting)。对比训练准确率、测试准确率、训练时间。
  1. 特征重要性验证:在随机森林中,把最重要的特征删除后重新训练,观察测试准确率下降幅度。验证特征重要性的可靠性。
  1. 实际选型:假设你要做一个"预测用户是否会购买"的任务,数据包含:用户年龄、收入、历史购买金额、最近 30 天浏览商品列表(文本)、用户头像(图像)。设计一个模型方案,说明每部分数据用什么模型处理,最后如何融合。