✨ 欢迎关注 ✨
本节介绍:如何用统计检验DeLong Test比较不同机器学习模型的ROC曲线性能差异。数据采用模拟数据,作者根据个人对机器学习的理解进行代码实现与图表输出,仅供参考。 完整 数据和代码将在稍后上传至交流群,成员可在交流群中获取下载。需要的朋友可关注公众文末提供的获取方式。 获取 前请咨询,避免不必要的问题。
✨ 文献信息 ✨
在这篇文献中,DeLong Test被用于比较不同机器学习模型在急性肾损伤(AKI)预测中的 ROC曲线的AUC(曲线下面积)差异,目的是评估各个模型在预测性能上的显著性差异
文献中的机器学习模型首先进行了特征选择,使用SHAP方法对33个特征进行降维,最终选出一个具有最佳预测能力的随机森林(RF)模型。为了优化模型的表现,选择了最相关的8个特征,可以参考往期文章——期刊配图:多种机器学习算法结合SHAP特征贡献在递归特征选择中的运用,通过比较不同模型的 AUC值,DeLong Test帮助研究人员判断哪些模型在预测急性肾损伤(AKI)的风险时表现更好。具体来说,AUC值越大,模型的预测性能就越好。因此,DeLong Test的作用是确认两种或多种模型在AUC上的差异是否足够显著,从而决定哪个模型的预测性能更优。如果DeLong Test的p值小于显著性水平(通常为0.05),则说明模型之间的AUC差异是显著的,这表明不同模型在预测任务中的性能存在实质性的差异,有助于选择性能最优的模型
接下来将展示如何利用DeLong Test检验两个模型之间的AUC值是否存在显著性差异, 传统的做法是 通过AUC值(当然还有其它评价指标综合比较考虑)的大小来比较模型性能。以二分类问题为例,单纯比较模型的评价指标,认为AUC值较大的模型性能较好,而DeLong Test能够提供统计学依据,确保模型性能差异具有显著性
✨ 基础代码 ✨
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Times New Roman'
plt.rcParams['axes.unicode_minus'] = False
import warnings
# 忽略所有警告
warnings.filterwarnings("ignore")
df = pd.read_csv('2025-6-18公众号Python机器学习AI.csv')
from sklearn.model_selection import train_test_split
# 划分特征和目标变量
X = df.drop(['target'], axis=1)
y = df['target']
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.3,
random_state=42,
stratify=df['target']
)
from sklearn.ensemble import RandomForestClassifier
import xgboost as xgb
from sklearn.neighbors import KNeighborsClassifier
# 初始化三个模型:Random Forest、XGBoost 和 KNN
model_rf = RandomForestClassifier(random_state=42)
model_xgb = xgb.XGBClassifier(random_state=42)
model_knn = KNeighborsClassifier(n_neighbors=5) # n_neighbors 设置为5
# 训练三个模型
model_rf.fit(X_train, y_train)
model_xgb.fit(X_train, y_train)
model_knn.fit(X_train, y_train)
# 绘制不同模型的ROC曲线
plt.figure(figsize=(8, 6))
plot_roc_curve(model_rf, X_test, y_test, 'RF') # 传入模型 测试集的自变量和因变量 以及模型名用于图列展示
plot_roc_curve(model_xgb, X_test, y_test, 'XGBoost')
plot_roc_curve(model_knn, X_test, y_test, 'KNN')
# 绘制随机分类的参考线
plt.plot([0, 1], [0, 1], 'r--', linewidth=1.5, alpha=0.8)
# 图形细节设置
plt.title("ROC Curve - Test Set Model Comparison", fontsize=20, fontweight="bold")
plt.xlabel("False Positive Rate (1-Specificity)", fontsize=18)
plt.ylabel("True Positive Rate (Sensitivity)", fontsize=18)
plt.xticks(fontsize=16)
plt.yticks(fontsize=16)
plt.legend(loc="lower right", fontsize=12)
# 去除顶部和右侧边框
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['left'].set_linewidth(1.5)
plt.gca().spines['bottom'].set_linewidth(1.5)
# 关闭网格线
plt.grid(False)
plt.savefig("1.pdf", format='pdf', bbox_inches='tight', dpi=1200)
plt.tight_layout()
plt.show()
使用三个机器学习模型(Random Forest、XGBoost 和 KNN)在训练集上进行训练,并在测试集上绘制这些模型的ROC曲线,用于比较它们的分类性能,其中plot_roc_curve是自定义函数,用于绘制每个模型的ROC曲线
import scipy.stats as st
from sklearn import metrics
class DelongTest():
def __init__(self, preds1, preds2, label, threshold=0.05):
'''
preds1: the output of model1
preds2: the output of model2
label : the actual label
'''
self._preds1 = preds1
self._preds2 = preds2
self._label = label
self.threshold = threshold
self._show_result()
def _auc(self, X, Y) -> float:
return 1 / (len(X) * len(Y)) * sum([self._kernel(x, y) for x in X for y in Y])
def _kernel(self, X, Y) -> float:
'''Mann-Whitney statistic'''
return 0.5 if Y == X else int(Y < X)
def _structural_components(self, X, Y) -> list:
V10 = [1 / len(Y) * sum([self._kernel(x, y) for y in Y]) for x in X]
V01 = [1 / len(X) * sum([self._kernel(x, y) for x in X]) for y in Y]
return V10, V01
def _get_S_entry(self, V_A, V_B, auc_A, auc_B) -> float:
return 1 / (len(V_A) - 1) * sum([(a - auc_A) * (b - auc_B) for a, b in zip(V_A, V_B)])
def _z_score(self, var_A, var_B, covar_AB, auc_A, auc_B):
return (auc_A - auc_B) / ((var_A + var_B - 2 * covar_AB) ** 0.5 + 1e-8)
def _group_preds_by_label(self, preds, actual) -> list:
X = [p for (p, a) in zip(preds, actual) if a]
Y = [p for (p, a) in zip(preds, actual) if not a]
return X, Y
def _compute_z_p(self):
X_A, Y_A = self._group_preds_by_label(self._preds1, self._label)
X_B, Y_B = self._group_preds_by_label(self._preds2, self._label)
V_A10, V_A01 = self._structural_components(X_A, Y_A)
V_B10, V_B01 = self._structural_components(X_B, Y_B)
auc_A = self._auc(X_A, Y_A)
auc_B = self._auc(X_B, Y_B)
# Compute entries of covariance matrix S (covar_AB = covar_BA)
var_A = (self._get_S_entry(V_A10, V_A10, auc_A, auc_A) * 1 / len(V_A10) + self._get_S_entry(V_A01, V_A01, auc_A, auc_A) * 1 / len(V_A01))
var_B = (self._get_S_entry(V_B10, V_B10, auc_B, auc_B) * 1 / len(V_B10) + self._get_S_entry(V_B01, V_B01, auc_B, auc_B) * 1 / len(V_B01))
covar_AB = (self._get_S_entry(V_A10, V_B10, auc_A, auc_B) * 1 / len(V_A10) + self._get_S_entry(V_A01, V_B01, auc_A, auc_B) * 1 / len(V_A01))
# Two tailed test
z = self._z_score(var_A, var_B, covar_AB, auc_A, auc_B)
p = st.norm.sf(abs(z)) * 2
return z, p
def _show_result(self):
z, p = self._compute_z_p()
print(f"z score = {z:.5f};\np value = {p:.5f};")
if p < self.threshold:
print("There is a significant difference")
else:
print("There is NO significant difference")
return z, p # 返回 z 和 p 值,以便后续使用
定义一个DelongTest类,用于通过DeLong Test检验两个模型的 AUC 值是否存在显著性差异,计算z值和p值,并根据p值判断模型之间的差异是否具有统计学显著性
# 获取预测结果(概率)
preds_rf = model_rf.predict_proba(X_test)[:, 1] # 预测为1的概率
preds_xgb = model_xgb.predict_proba(X_test)[:, 1]
preds_knn = model_knn.predict_proba(X_test)[:, 1]
# 初始化三个模型:Random Forest、XGBoost 和 KNN
models = {
'Random Forest': model_rf,
'XGBoost': model_xgb,
'KNN': model_knn
}
# 生成所有模型组合对
model_combinations = [
('Random Forest', 'KNN'),
('Random Forest', 'XGBoost'),
('KNN', 'XGBoost')
]
# 循环对每个组合进行DeLong Test
for model1_name, model2_name in model_combinations:
# 获取对应模型的预测概率
preds1 = models[model1_name].predict_proba(X_test)[:, 1]
preds2 = models[model2_name].predict_proba(X_test)[:, 1]
print(f"\nComparing {model1_name} vs {model2_name}:")
delong_test = DelongTest(preds1=preds1, preds2=preds2, label=y_test)
对前面训练的三个模型(Random Forest、XGBoost 和 KNN)两两组合进行DeLong Test,检验它们在测试集上预测的 AUC 值是否存在显著性差异
Comparing Random Forest vs KNN:
z score = 4.37177;
p value = 0.00001;
There is a significant difference
Comparing Random Forest vs XGBoost:
z score = 0.94518;
p value = 0.34457;
There is NO significant difference
Comparing KNN vs XGBoost:
z score = -3.81528;
p value = 0.00014;
There is a significant difference
结果表明:RF和KNN、KNN和XGBoost的AUC差异具有显著性,而RF与XGBoost的差异不显著,说明后两者在分类性能上相当,KNN显著较差,当然最终如果要确定唯一一个最优模型,根据AUC值最大的确定最优模型为RF
✨ 该文章案例 ✨
在上传至交流群的文件中,像往期文章一样,将对案例进行逐步分析,确保读者能够达到最佳的学习效果。内容都经过详细解读,帮助读者深入理解模型的实现过程和数据分析步骤,从而最大化学习成果。
同时,结合提供的免费AI聚合网站进行学习,能够让读者在理论与实践之间实现融会贯通,更加全面地掌握核心概念。
✨ 介绍 ✨
本节介绍到此结束,有需要学习数据分析和Python机器学习相关的朋友欢迎到淘宝店铺:Python机器学习AI,或添加作者微信deep_ML联系,获取作者的公众号合集。截至目前为止,合集已包含近300多篇文章,购买合集的同时,还将提供免费稳定的AI大模型使用。
更新的内容包含数据、代码、注释和参考资料。 作者仅分享案例项目,不提供额外的答疑服务。项目中将提供详细的代码注释和丰富的解读,帮助您理解每个步骤 。 获取 前请咨询,避免不必要的问题。
✨ 群友反馈 ✨
✨ 淘宝店铺 ✨
请大家打开淘宝扫描上方的二维码,进入店铺,获取更多Python机器学习和AI相关的内容,或者添加作者微信deep_ML联系 避免淘宝客服漏掉信息 ,希望能为您的学习之路提供帮助!
✨ 免费赠书 ✨
支持知识分享,畅享学习乐趣!特别感谢清华大学出版社 对本次赠书活动的鼎力支持!即日起,只需点赞、推荐、转发 此文章,作者将从后台随机抽取一位幸运儿,免费包邮赠送清华出版社提供的《CUDA并行编程与性能优化》这本精彩书籍📚!
💡 赶快参与,一键三连,说不定你就是那位幸运读者哦!
往期推荐
期刊复现:连续数据与分类数据共存的SHAP可视化散点图与箱形图组合形式
期刊复现:多分类任务如何拆分为二分类任务并进行堆叠预测提高模型预测性能
期刊配图:SHAP值分析模型可解释性在柱状图与蜂窝图中的进阶组合展示
期刊配图:通过堆叠Mean|SHAP|展示不同区间对模型贡献度的可视化分析
期刊复现:利用UMAP降维算法可视化深度学习随着训练次数的增加模型区分能力的变化
期刊配图:PCA、t-SNE与UMAP三种降维方法简化高维数据的展示应用对比
Science期刊复现:分类、回归与Shap分析多角度揭示同一数据集变量对目标的影响
多模型SHAP+PDP解读Stacking集成模型:从基学习器到元学习器的可解释性与模型调参实现
如果你对类似于这样的文章感兴趣。
欢迎关注、点赞、转发~
个人观点,仅供参考