You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

交叉验证AUROC绘图、最优阈值确定及AUC计算准确性问询

交叉验证ROC曲线与阈值、AUC计算的疑问

我在做机器学习模型交叉验证评估时遇到两个核心问题:

  1. 已经能绘制每折的AUROC和对应阈值,但不确定如何准确绘制所有折的平均AUROC及其对应阈值,自己加了代码但拿不准正确性。
  2. 发现用np.mean()计算的平均AUC和sklearn.metrics.auc()基于平均ROC曲线计算的AUC有差异,想知道哪种方法更精准。

以下是我修改后的代码:

X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)

cv = StratifiedKFold(n_splits=10)
classifier = SVC(kernel='sigmoid',probability=True,random_state=0)

tprs = []
aucs = []
optimal_thresholds = []
mean_fpr = np.linspace(0, 1, 100)
plt.figure(figsize=(10,10))
i = 0
for train, test in cv.split(X, y):
    probas_ = classifier.fit(X[train], y[train]).predict_proba(X[test])
    # Compute ROC curve and area the curve
    fpr, tpr, thresholds = roc_curve(y[test], probas_[:, 1])

    # 我添加的代码:
    optimal_threshold_index = np.argmax(tpr-fpr)
    optimal_threshold = thresholds[optimal_threshold_index]
    optimal_thresholds.append(optimal_threshold)
    #

    tprs.append(np.interp(mean_fpr, fpr, tpr))
    tprs[-1][0] = 0.0
    roc_auc = auc(fpr, tpr)
    aucs.append(roc_auc)
    plt.plot(fpr, tpr, lw=1, alpha=0.3,
             label='ROC fold %d (AUC = %0.4f)' % (i, roc_auc))

    i += 1



plt.plot([0, 1], [0, 1], linestyle='--', lw=2, color='r',
         label='Chance', alpha=.8)

mean_tpr = np.mean(tprs, axis=0)
mean_tpr[-1] = 1.0


mean_auc = auc(mean_fpr, mean_tpr)

# 我添加的代码:
np_mean_AUC = np.mean(aucs)
# print(f"np_mean_AUC={np_mean_AUC},mean_auc={mean_auc}")
#

std_auc = np.std(aucs)

plt.plot(mean_fpr, mean_tpr, color='b',
         label=r'Mean ROC (AUC = %0.4f $\pm$ %0.4f)' % (np_mean_AUC, std_auc),
         lw=2, alpha=.8)

# 我添加的代码:
mean_optimal_threshold_index = np.argmax(mean_tpr-mean_fpr)
plt.annotate(f'Mean Optimal Threshold ({np.mean(optimal_thresholds):.2f})',
                xy=(mean_fpr[mean_optimal_threshold_index], mean_tpr[mean_optimal_threshold_index]),
                xytext=(5, -5),
                textcoords='offset points',
                arrowprops=dict(facecolor='red', arrowstyle='wedge,tail_width=0.7', shrinkA=0, shrinkB=10),
                color='red')
#

std_tpr = np.std(tprs, axis=0)
tprs_upper = np.minimum(mean_tpr + std_tpr, 1)
tprs_lower = np.maximum(mean_tpr - std_tpr, 0)
plt.fill_between(mean_fpr, tprs_lower, tprs_upper, color='grey', alpha=.2,
                 label=r'$\pm$ 1 std. dev.')

plt.xlim([-0.01, 1.01])
plt.ylim([-0.01, 1.01])
plt.xlabel('False Positive Rate',fontsize=18)
plt.ylabel('True Positive Rate',fontsize=18)
plt.title('Cross-Validation ROC of SVM',fontsize=18)
plt.legend(loc="lower right", prop={'size': 15})
plt.show()

输出的ROC曲线如图所示:
交叉验证ROC曲线

请帮忙判断:

  • 我添加的代码是否能准确绘制交叉验证的平均ROC曲线及对应阈值?
  • 标注的AUC值是否合理?

问题解答

一、关于平均ROC与阈值的绘制正确性

你添加的代码逻辑整体合理,但有几个细节需要明确:

1. 单折最优阈值的计算

你用np.argmax(tpr-fpr)找最优阈值,这是基于Youden指数的常用阈值选择策略,逻辑没问题。收集每折最优阈值后取平均,是一种合理的汇总方式,但要注意:

  • 不同折的阈值分布可能差异较大,取平均可能掩盖个体差异,若想更严谨,可补充绘制阈值分布箱线图辅助说明。

2. 平均ROC上的阈值标注

你在平均ROC曲线上用np.argmax(mean_tpr-mean_fpr)找到的点,是平均ROC曲线上的Youden指数最大值点,但这个点和你取平均的optimal_thresholds没有直接对应关系——因为平均ROC是各折TPR在统一FPR网格上插值后取平均得到的虚拟曲线,本身没有原始阈值序列。

你当前把“各折最优阈值的平均值”和“平均ROC上的Youden点”绑定标注的方式,可作为近似展示,但需要明确:这个阈值是各折最优阈值的统计平均值,而非平均ROC曲线本身对应的阈值。

如果想更严谨地关联平均ROC与阈值,可尝试对各折阈值进行插值对齐:

# 在循环中添加阈值插值
interp_thresholds = np.interp(mean_fpr, fpr, thresholds)
threshold_list.append(interp_thresholds)

# 之后计算平均阈值
mean_thresholds = np.mean(threshold_list, axis=0)
# 找到平均ROC上Youden点对应的平均阈值
mean_opt_thresh = mean_thresholds[np.argmax(mean_tpr - mean_fpr)]
# 标注时用这个值
plt.annotate(f'Mean Optimal Threshold ({mean_opt_thresh:.2f})', ...)

但要注意,插值后的阈值是近似值,因为原始阈值和FPR的对应关系是非线性的。

二、两种AUC计算方式的差异与精准性

np.mean(aucs)和auc(mean_fpr, mean_tpr)的差异是正常的,二者统计意义不同:

  1. np.mean(aucs):各折AUC的算术平均值

    • 逻辑:先计算每折测试集的ROC曲线AUC,再取平均。
    • 意义:直接反映模型在不同数据子集上的AUC表现平均水平,是交叉验证中评估模型泛化能力的标准方式。
  2. auc(mean_fpr, mean_tpr):平均ROC曲线的AUC

    • 逻辑:先对各折TPR在统一FPR网格上插值得到平均TPR曲线,再计算该曲线的AUC。
    • 意义:仅反映聚合后的虚拟ROC曲线的面积,不对应任何实际测试集的模型表现,更多用于可视化展示整体趋势。

哪种更精准?
若目标是评估模型泛化能力,np.mean(aucs)是更合理、精准的选择——它直接基于每折真实测试集的评估结果,符合交叉验证估计模型真实性能的核心目的。你当前在图例中标注np_mean_AUC是合理的,建议保留。

三、代码优化建议

  • 添加最优阈值分布可视化:用plt.boxplot(optimal_thresholds)展示各折阈值的离散程度,让结果更完整。
  • 若追求平均ROC与阈值的严格对应,可采用上述阈值插值对齐的方式,但需接受插值带来的近似误差。

内容的提问来源于stack exchange,提问作者Alexander Xie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 12:58:23