共计 2546 个字符,预计需要花费 7 分钟才能阅读完成。
小样本数据的决策树挑战
当数据集仅有 100 组样本时,决策树训练会面临两个典型问题:

- 过拟合风险 :树深度过大时,模型会记住训练数据的噪声而非规律。例如当
max_depth=10时,可能为每个样本创建单独分支 - 特征重要性偏差:少量特征可能因偶然相关性被误判为重要。比如某个特征在 20% 样本中恰好与标签同步变化
数学上,过拟合可通过泛化误差分解解释:
$$\text{Error} = \text{Bias}^2 + \text{Variance} + \text{Irreducible Error}$$
小样本下 Variance 项会显著增加
算法选型:为什么选择 CART
三种主流算法的对比:
- ID3:仅支持离散特征,用信息增益选择划分属性,易偏向取值多的特征
- C4.5:改进信息增益比,但仍需离散化处理连续特征
- CART:本文选择,优势包括:
- 直接支持连续特征(二分裂方式)
- 基尼系数计算效率高于信息熵
- 天然适合二分类任务
实战代码演示
数据预处理
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
# 假设原始数据已加载为 df
features = df.iloc[:, :-1] # 取所有特征
labels = df.iloc[:, -1] # 最后一列为标签
# MinMax 缩放:将特征压缩到 [0,1] 区间
scaler = MinMaxScaler()
# 重要:只在训练集上 fit,避免数据泄露
scaled_features = scaler.fit_transform(features)
模型训练与调参
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
# 参数网格示例
param_grid = {'max_depth': [3, 5, 7], # 控制树复杂度
'min_samples_split': [2, 5, 10] # 节点继续分裂的最小样本数
}
# 使用 5 折交叉验证
grid_search = GridSearchCV(DecisionTreeClassifier(criterion='gini'),
param_grid,
cv=5,
scoring='accuracy'
)
grid_search.fit(scaled_features, labels)
# 输出最佳参数
print(f"最佳参数: {grid_search.best_params_}")
决策树可视化
from sklearn.tree import export_graphviz
import graphviz
best_model = grid_search.best_estimator_
dot_data = export_graphviz(
best_model,
out_file=None,
feature_names=df.columns[:-1],
class_names=['Class0', 'Class1'],
filled=True,
rounded=True
)
graph = graphviz.Source(dot_data)
graph.render("decision_tree") # 生成 PDF 文件
关键避坑策略
特征不足时的增强方法
当特征数少于 10 时,可采用 Bootstrap 采样:
- 从原始数据有放回地抽取 100 个样本
- 随机选择部分特征子集(如 50%)
- 重复生成多棵树构成随机森林
交叉验证实现
from sklearn.model_selection import cross_val_score
scores = cross_val_score(
best_model,
scaled_features,
labels,
cv=5, # 5 折
scoring='precision' # 可根据需求改为 recall/f1
)
print(f"交叉验证精度: {scores.mean():.2f}±{scores.std():.2f}")
特征筛选
importances = best_model.feature_importances_
# 筛选重要性 >5% 的特征
selected_idx = np.where(importances > 0.05)[0]
print(f"有效特征: {df.columns[selected_idx]}")
模型评估与优化
性能指标分析
from sklearn.metrics import classification_report
preds = best_model.predict(scaled_features)
print(classification_report(labels, preds))
报告示例:
precision recall f1-score support
0 0.93 0.89 0.91 54
1 0.88 0.93 0.90 46
accuracy 0.91 100
macro avg 0.91 0.91 0.91 100
weighted avg 0.91 0.91 0.91 100
召回率与精确度平衡
当需要优化特定类别时:
-
调整分类阈值(默认 0.5)
probs = best_model.predict_proba(scaled_features)[:, 1] # 提高阈值增加精确度 high_precision_preds = (probs > 0.7).astype(int) -
使用 class_weight 参数
model = DecisionTreeClassifier(class_weight={0:1, 1:2}) # 类别 1 权重加倍
延伸思考
尝试回答以下问题来深化理解:
- 当把 max_depth 从 3 增加到 10 时,测试集准确率反而下降 2%,可能是什么原因?
- 如果用相同数据训练 GBDT 模型,哪些参数需要额外调整?
- 特征重要性排名前三的特征在 XGBoost 中是否仍然重要?如何验证?
建议通过修改以下代码进行对比实验:
from sklearn.ensemble import GradientBoostingClassifier
gbdt = GradientBoostingClassifier(
n_estimators=100,
learning_rate=0.1,
max_depth=3
)
gbdt.fit(scaled_features, labels)
正文完
发表至: 未分类
近两天内
