sklearn与TensorFlow中ROC AUC/PR AUC结果差异原因探究
问题背景
我用代码生成了一个二元分类虚拟任务,分别基于Sklearn和TensorFlow计算ROC AUC与PR AUC指标。哪怕设置了num_thresholds=10**6的超大阈值数量,两者的结果还是有大约0.4%的差异,想知道这是为什么?
测试代码
import tensorflow as tf import numpy as np from sklearn.metrics import roc_auc_score, average_precision_score from sklearn.datasets import make_classification # Custom ROC AUC and PR AUC functions using sklearn def sk_roc_auc(y_true, y_pred): return tf.py_function(roc_auc_score, (y_true, y_pred), tf.double) def sk_pr_auc(y_true, y_pred): return tf.py_function(average_precision_score, (y_true, y_pred), tf.double) # Create a synthetic dataset for binary classification X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_redundant=10, random_state=42) train_size = int(0.8 * len(X)) X_train, X_test = X[:train_size], X[train_size:] y_train, y_test = y[:train_size], y[train_size:] # Create TensorFlow Dataset train_dataset = tf.data.Dataset.from_tensor_slices((X_train, y_train)).batch(32) test_dataset = tf.data.Dataset.from_tensor_slices((X_test, y_test)).batch(32) # Build a simple model model = tf.keras.Sequential([ tf.keras.layers.Input(shape=(20,)), tf.keras.layers.Dense(32, activation='relu'), tf.keras.layers.Dense(1, activation='sigmoid') ]) # Compile the model model.compile(optimizer='adam', loss='binary_crossentropy', metrics=[ tf.keras.metrics.AUC(num_thresholds=10**6, name='tf_roc_auc', curve='ROC'), tf.keras.metrics.AUC(num_thresholds=10**6, name='tf_pr_auc', curve='PR'), sk_roc_auc, sk_pr_auc ]) # Train the model model.fit(train_dataset, epochs=10, validation_data=test_dataset)
运行输出(最后一轮)
Epoch 10/10 25/25 [==============================] - 2s 100ms/step - loss: 0.2217 - tf_roc_auc: 0.9786 - tf_pr_auc: 0.9777 - sk_roc_auc: 0.9820 - sk_pr_auc: 0.9820 - val_loss: 0.2908 - val_tf_roc_auc: 0.9490 - val_tf_pr_auc: 0.9452 - val_sk_roc_auc: 0.9367 - val_sk_pr_auc: 0.9425
差异原因解析
数值精度与计算方式差异
TensorFlow内置AUC默认使用float32精度做运算,而Sklearn的指标计算默认用更高精度的float64。即使阈值数量很大,浮点运算的舍入误差累积后会导致结果偏差。另外,TensorFlow按批次累积计算指标,中间步骤的精度损失会被放大;而Sklearn是一次性计算全量样本,精度损失更少。阈值选取逻辑不同
TensorFlow的AUC是均匀采样阈值,哪怕设置10^6个阈值,也无法完全覆盖所有样本的独特预测值(尤其是预测值分布不均匀时);而Sklearn的ROC AUC是基于所有独特预测值作为阈值,PR AUC则用精确插值法计算曲线下面积,不会错过关键阈值点,计算更精准。PR AUC的核心计算逻辑差异
Sklearn的average_precision_score是对召回率区间的精度做加权求和,权重为召回率的变化量,严格遵循PR曲线的精确积分;而TensorFlow的PR AUC是通过采样阈值得到点后,用梯形法近似计算面积,这种近似方法本身就会带来误差,和Sklearn的加权求和逻辑本质不同。训练阶段的指标计算时机差异
TensorFlow内置指标是按批次累积更新,每处理一个批次就用当时的模型预测结果更新指标;而Sklearn指标是在每个epoch结束后,用最终的模型对全量样本做一次预测再计算。训练过程中模型权重逐步更新,两种方式的预测输入本身就有细微差异,最终导致指标结果偏差。
内容的提问来源于stack exchange,提问作者user1337

