问题与目标

单树容易解释但对数据变化敏感,Bagging 通过并行多样性降低方差,Boosting 则按顺序纠正旧错误。
决策树用一系列条件切分数据,容易解释但容易过拟合。集成学习组合多个模型,提高稳定性或逐步纠正错误。
完成标准:比较决策树、随机森林和梯度提升在训练集与测试集的表现,观察树深度的影响。
核心概念
树在候选特征与阈值中选择能降低不纯度的切分。树越深越能拟合训练细节,也越容易学习噪声。限制深度、叶节点样本数或剪枝可控制复杂度。
随机森林属于 Bagging:对样本和特征引入随机性,训练多棵树后投票。Boosting 顺序训练弱模型,让后续模型重点修正前面的错误。特征重要性只表示模型使用程度,不证明因果。
一次分裂在做什么
分类树尝试候选特征和阈值,把样本分成两组,并选择能最大降低不纯度的切分。Gini 不纯度在单一类别节点为 0,类别越混杂越大。回归树则常按平方误差下降选择切分。
树不断切分直到停止条件满足。常用控制项包括 max_depth、min_samples_split、min_samples_leaf 和剪枝强度 ccp_alpha。这些参数限制模型容量,应在交叉验证中选择。
Bagging 和 Boosting 的区别
| 维度 | Bagging/随机森林 | Boosting |
|---|---|---|
| 训练关系 | 多模型相对独立 | 后一模型纠正前者 |
| 主要目标 | 降低方差 | 逐步降低偏差 |
| 并行性 | 较容易并行 | 顺序依赖更强 |
| 对噪声 | 通常较稳健 | 可能持续关注噪声 |
可运行实现
from sklearn.datasets import make_classification
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
X, y = make_classification(
n_samples=1200, n_features=10, n_informative=6,
flip_y=0.08, random_state=42,
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, stratify=y, random_state=42,
)
models = [
DecisionTreeClassifier(random_state=42),
DecisionTreeClassifier(max_depth=4, random_state=42),
RandomForestClassifier(n_estimators=150, max_depth=7, random_state=42, n_jobs=-1),
GradientBoostingClassifier(random_state=42),
]
for model in models:
model.fit(X_train, y_train)
train_score = accuracy_score(y_train, model.predict(X_train))
test_score = accuracy_score(y_test, model.predict(X_test))
print(type(model).__name__, round(train_score, 3), round(test_score, 3))
输入是含噪声的固定随机分类数据,输出为训练与测试准确率。未限制的单树通常训练分数很高,测试差距揭示过拟合。
决策路径与重要性
单树可以用 export_text(tree, feature_names=...) 导出条件,检查是否使用不合理字段。随机森林的 feature_importances_ 基于不纯度下降,偏好可切分点较多的连续或高基数特征。
更稳妥的检查是在验证集随机打乱某个特征,观察指标下降,即置换重要性。重要性高只说明模型依赖该字段,字段仍可能是泄漏或代理变量,必须结合数据生成过程审查。
导出单树规则
在数据上表现良好但无法解释的规则,很可能用到了泄漏字段。为特征命名后可直接导出浅树:
from sklearn.tree import export_text
feature_names = [f"feature_{index}" for index in range(X.shape[1])]
shallow_tree = DecisionTreeClassifier(
max_depth=3, min_samples_leaf=20, random_state=42
)
shallow_tree.fit(X_train, y_train)
print(export_text(shallow_tree, feature_names=feature_names))
阈值条件只是模型在当前数据上学到的分割,不是通用业务规则。换一个时间段或随机种子后首层切分就变化,说明规则不稳定。
用置换重要性复核特征
from sklearn.inspection import permutation_importance
forest = models[2]
result = permutation_importance(
forest,
X_test,
y_test,
scoring="accuracy",
n_repeats=10,
random_state=42,
)
ranking = sorted(
zip(feature_names, result.importances_mean, result.importances_std),
key=lambda item: item[1],
reverse=True,
)
for name, mean_drop, std_drop in ranking[:5]:
print(name, round(mean_drop, 3), "+/-", round(std_drop, 3))
每次打乱一个特征,并观察测试指标下降幅度。重复打乱可以给出波动范围。高度相关的特征可以相互替代,导致它们的单项重要性都偏低,所以结果仍需结合相关性和业务含义。
复杂度实验如何解读
| 现象 | 可能原因 | 下一步 |
|---|---|---|
| 训练高、测试低 | 树太深,叶子过小 | 限制深度、增大叶节点样本数 |
| 训练和测试都低 | 特征信息不足或限制过强 | 检查特征与放宽复杂度 |
| 不同划分差异大 | 样本少、噪声大或分布不稳定 | 交叉验证并查分组/时间漂移 |
| 集成只小幅提升 | 单树已足够或错误高度相关 | 比较运维成本,不强行上复杂模型 |
进一步验证
- 使用
max_depth为 2、4、8 和不限制的四个单树,记录训练与测试差距。 - 导出一棵三层树,核对前两个切分特征是否在预测时可用。
- 对随机森林计算置换重要性,报告均值、波动和可能的相关特征干扰。
常见问题与排查
- 只看训练准确率:同时报告独立验证和测试表现。
- 随机森林树越多越好:收益会递减,训练、内存和推理成本增加。
- 根据内置重要性删除字段:先检查高基数偏差和稳定性,可补充置换重要性。
- Boosting 对异常值敏感:检查数据质量和损失函数。
小结
单树提供清晰条件边界,随机森林用并行多样性提高稳定性,Boosting 逐步纠错。集成不是自动正确,仍需控制复杂度和独立评估。
License: CC BY-NC 4.0
Updated 2 hours ago
Was this article helpful? Give it a like.
0 comments


