CART决策树案例实战:从特征工程到模型调优的全流程解析

1次阅读
没有评论

共计 2833 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

为什么选择 CART 决策树

CART 决策树在金融风控中能清晰展现规则逻辑,满足监管可解释性要求;医疗诊断场景下其白盒特性便于医生理解特征贡献度;相比神经网络,它在中小规模数据上训练更快且无需 GPU 资源。今天我们就用一个真实案例,拆解从数据清洗到模型部署的全流程。

CART 决策树案例实战:从特征工程到模型调优的全流程解析

实战中的四大痛点

1. 特征缺失值处理陷阱

  • 直接删除缺失样本可能导致重要模式丢失
  • 用均值填充数值特征时,需警惕扭曲分布(特别是偏态数据)
  • 推荐方案:对连续变量使用 SimpleImputer(strategy='median'),分类变量用most_frequent 策略

2. 类别不平衡引发的偏差

  • 正负样本 7:3 时,准确率指标可能虚高
  • 解决方案组合拳:
  • 设置class_weight='balanced'
  • 使用 SMOTE 过采样(注意仅在训练集操作)
  • 改用 F1-score 作为评估指标

3. 树深度与过拟合的生死局

  • 通过预剪枝(pre-pruning)控制复杂度:
    DecisionTreeClassifier(
        max_depth=5,
        min_samples_leaf=10,
        ccp_alpha=0.01  # 代价复杂度剪枝
    )
  • 后剪枝(post-pruning)步骤:
  • 先训练完整树
  • 计算cost_complexity_pruning_path
  • 选择使验证集准确率最高的 alpha

技术方案实现

特征工程 Pipeline

from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline

# 数值型特征处理链
num_pipe = Pipeline([('imputer', SimpleImputer(strategy='median')),
    ('scaler', RobustScaler())  # 对离群值鲁棒
])

# 类别型特征处理链
cat_pipe = Pipeline([
    ('encoder', OrdinalEncoder(handle_unknown='use_encoded_value',
                              unknown_value=-1)),
    ('imputer', SimpleImputer(strategy='constant', fill_value=-2))
])

# 组合处理器
preprocessor = ColumnTransformer(
    transformers=[('num', num_pipe, numerical_cols),
        ('cat', cat_pipe, categorical_cols)
    ])

基尼系数 vs 信息增益

我们通过控制变量实验对比分裂标准:

for criterion in ['gini', 'entropy']:
    clf = DecisionTreeClassifier(criterion=criterion)
    scores = cross_val_score(clf, X, y, cv=5)
    print(f"{criterion}: {scores.mean():.3f} ± {scores.std():.3f}")

实验发现:
– 基尼系数计算更快(无需 log 运算)
– 信息增益对类别分布更敏感
– 实际差异通常 <1%,建议优先选择 gini

超参数网格搜索

from sklearn.model_selection import GridSearchCV

param_grid = {'max_depth': [3, 5, 7, None],
    'min_samples_split': [2, 5, 10],
    'min_impurity_decrease': [0, 0.001, 0.01]
}

grid = GridSearchCV(estimator=DecisionTreeClassifier(),
    param_grid=param_grid,
    scoring='roc_auc',
    n_jobs=-1,
    cv=5
)
grid.fit(X_train, y_train)

关键技巧:
– 设置 n_jobs=-1 充分利用多核
– 早停机制:early_stopping=True可加速搜索
– 内存控制:大数据集时减小 cv 值

可视化与评估

决策树结构导出

import graphviz
from sklearn.tree import export_graphviz

dot_data = export_graphviz(
    model,
    out_file=None,
    feature_names=feature_names,
    class_names=['0', '1'],
    filled=True,
    rounded=True
)
graph = graphviz.Source(dot_data)
graph.render('decision_tree')  # 生成 PDF

特征重要性分析

import matplotlib.pyplot as plt

plt.barh(feature_names, model.feature_importances_)
plt.xlabel("Feature Importance")
plt.title("Top Predictive Features")
plt.tight_layout()

ROC 曲线绘制

from sklearn.metrics import RocCurveDisplay

RocCurveDisplay.from_estimator(
    model,
    X_test,
    y_test,
    name="CART Tree",
    plot_chance_level=True
)
plt.show()

生产环境避坑指南

  1. 类别特征编码
  2. 必须使用 OrdinalEncoder 而非 LabelEncoder
  3. 原因:LabelEncoder 会引入虚假的大小关系
  4. 正确做法:

    encoder = OrdinalEncoder(categories=[['low', 'medium', 'high']],  # 显式定义顺序
        handle_unknown='use_encoded_value',
        unknown_value=-1
    )

  5. 样本权重配置

  6. 当正负样本比达 1:100 时:
    class_weight={0: 1, 1: 100}  # 等价于 balanced
  7. 更精细控制:

    sample_weight = np.where(y == 1, 10, 1)
    model.fit(X, y, sample_weight=sample_weight)

  8. 线程安全陷阱

  9. sklearn 的决策树原生非线程安全
  10. 解决方案:
    • 预测时加锁
    • 或用joblib.parallel_backend('threading')
    • 推荐部署为微服务(如 Flask API)

延伸思考

当特征维度突破 1000 时:
– CART 树的训练时间呈指数增长(特征选择复杂度 O(m log m))
– 随机森林通过特征采样能更好处理高维稀疏性
– 建议测试方案:
1. 先用方差过滤低方差特征
2. 对比 CART 与 RF 的 AUC/ 训练耗时
3. 考虑梯度提升树(如 XGBoost)的折中方案

最终模型选择应综合考虑:业务解释性需求、实时性要求、硬件资源三大要素。希望这篇实战指南能帮助你少走弯路!

正文完
 0
评论(没有评论)