scikit-learn中DecisionTree与ExtraTree的ROC曲线异常问题咨询
问题描述
在二分类(是/否)任务中,使用scikit-learn训练多个分类器并绘制ROC曲线时,DecisionTreeClassifier()和ExtraTreeClassifier()的ROC曲线呈现异常形态,其他分类器曲线形态正常。尝试了scikit-learn所有绘制ROC曲线的函数,结果一致,需要指导如何优化模型或调整绘图方式。
原决策树代码如下:
model3 = make_pipeline(preprocessor, DecisionTreeClassifier()) model3[:-1].get_feature_names_out() m=model3[:-1].get_feature_names_out() model3 = model3.fit(data_train, target_train) plt.figure(figsize=(12,12)) plot_tree(model3.named_steps['decisiontreeclassifier'], fontsize=10, node_ids=True, feature_names=m, max_depth=5) cm3 = confusion_matrix(target_test, y_pred3, normalize='all') cm3_display = ConfusionMatrixDisplay(cm3).plot() plt.xlabel('Klasa predykowana – wynik testu') plt.ylabel('Klasa rzeczywista') plt.show() RocCurveDisplay.from_estimator(model3, data_test, target_test) plt.show() RocCurveDisplay.from_predictions(target_test, y_pred3) plt.show() model3_probs = model3.predict_proba(data_test) model3_probs = model3_probs[:, 1] model3_fpr, model3_tpr, _ = roc_curve(target_test, model3_probs) roc_auc = metrics.auc(model3_fpr, model3_tpr) display = metrics.RocCurveDisplay(fpr=model3_fpr, tpr=model3_tpr, roc_auc=roc_auc,estimator_name='example estimator') display.plot()
解决方案
一、模型优化(核心原因:决策树过拟合导致概率输出离散)
决策树和极端树默认无限制生长,极易过拟合训练数据,导致输出的预测概率只有少数离散值(甚至只有0和1),进而让ROC曲线形态异常。可以通过以下参数约束模型:
- 限制树的最大深度:设置
max_depth参数(如max_depth=5),避免树过度分裂,可通过交叉验证(GridSearchCV)选择最优深度。 - 增加叶节点最小样本数:设置
min_samples_leaf=5或min_samples_split=10,防止树在少量样本上分裂,降低过拟合风险。 - 启用代价复杂度剪枝:通过
ccp_alpha参数进行剪枝,可先调用model.cost_complexity_pruning_path()获取候选值,再用交叉验证选最优ccp_alpha。 - 处理类别不平衡:如果数据集存在类别不平衡,添加
class_weight='balanced'参数,让模型自动调整类别权重,避免偏向多数类。
二、绘图方式调整
- 避免用硬预测结果绘制ROC:
RocCurveDisplay.from_predictions()接收的是分类结果(0/1),只能生成单个点或少数几个点的曲线,这不是标准ROC曲线的绘制方式。必须使用模型输出的概率值(predict_proba()返回的正类概率)来绘制,即使用RocCurveDisplay.from_estimator()或手动计算FPR/TPR的方式。 - 检查预测概率的分布:先打印
model3_probs的唯一值,如果只有少数几个值,说明模型过拟合严重,需要优先优化模型。
调整后的代码示例
from sklearn.model_selection import GridSearchCV import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay, RocCurveDisplay, roc_curve, auc # 1. 优化决策树参数 param_grid = { 'decisiontreeclassifier__max_depth': [3,5,7], 'decisiontreeclassifier__min_samples_leaf': [3,5,10], 'decisiontreeclassifier__class_weight': ['balanced'] } model3 = make_pipeline(preprocessor, DecisionTreeClassifier()) grid_search = GridSearchCV(model3, param_grid, cv=5, scoring='roc_auc') grid_search.fit(data_train, target_train) model3 = grid_search.best_estimator_ # 2. 生成预测结果(补全原代码中缺失的y_pred3定义) y_pred3 = model3.predict(data_test) # 3. 绘制树结构 plt.figure(figsize=(12,12)) plot_tree(model3.named_steps['decisiontreeclassifier'], fontsize=10, node_ids=True, feature_names=model3[:-1].get_feature_names_out(), max_depth=5) plt.show() # 4. 混淆矩阵 cm3 = confusion_matrix(target_test, y_pred3, normalize='all') cm3_display = ConfusionMatrixDisplay(cm3).plot() plt.xlabel('预测类别 – 测试结果') plt.ylabel('真实类别') plt.show() # 5. 用模型直接绘制ROC(基于概率) RocCurveDisplay.from_estimator(model3, data_test, target_test, estimator_name='优化后的决策树') plt.show() # 6. 手动计算并绘制ROC model3_probs = model3.predict_proba(data_test)[:, 1] model3_fpr, model3_tpr, _ = roc_curve(target_test, model3_probs) roc_auc = auc(model3_fpr, model3_tpr) display = RocCurveDisplay(fpr=model3_fpr, tpr=model3_tpr, roc_auc=roc_auc, estimator_name='优化后的决策树') display.plot() plt.show()
内容的提问来源于stack exchange,提问作者PawelKinczyk
相关产品推荐
相关产品推荐

