手动计算TPR/FPR与scikit-learn ROC曲线输出结果不一致问题
问题原因与修正方案
这是代码编写错误+对scikit-learn接口默认逻辑理解偏差共同导致的,不属于函数设计的预期差异。
错误1:混淆矩阵的四类样本取值完全颠倒
scikit-learn的confusion_matrix输出矩阵遵循「行对应真实标签、列对应预测标签、标签按升序排列」的规则,布尔类型的升序为False < True,因此矩阵索引和样本类别的对应关系为:
cm[0,0]:真实为False、预测为False → 真负例(TN)cm[0,1]:真实为False、预测为True → 假正例(FP)cm[1,0]:真实为True、预测为False → 假负例(FN)cm[1,1]:真实为True、预测为True → 真正例(TP)
你原有代码把四个类别的定义完全写反,计算出的实际是负类的分类指标,因此数值和正类指标刚好呈「和为1」的互补关系:你算出的0.3611 = 1 - 0.6389,0.4567 = 1 - 0.5433,和roc_curve返回的中间值刚好互补。
错误2:对roc_curve的阈值逻辑理解不到位
你传入的是布尔类型的预测数组,roc_curve默认将排序靠后的大值标签(即布尔值True)作为正类,返回的阈值数组[2, 1, 0]是为了覆盖ROC曲线的三个关键节点:
- 阈值为2:所有样本预测值都小于2,全部判定为负类,对应FPR=0、TPR=0,是ROC曲线的左下角起点
- 阈值为1:判定规则为预测值≥1则判为正类,布尔值
True等价于数值1、False等价于0,此时的判定逻辑就是直接使用你传入的离散预测结果,对应的FPR、TPR就是该分类规则下的真实指标 - 阈值为0:所有样本预测值都≥0,全部判定为正类,对应FPR=1、TPR=1,是ROC曲线的右上角终点
修正方案
把混淆矩阵的四类样本取值按正确对应关系调整即可,修正后的代码如下:
from sklearn.metrics import confusion_matrix, roc_curve cm = confusion_matrix(self.real_values_discrete, self.predictions_discrete) _tn = cm[0, 0] _fp = cm[0, 1] _fn = cm[1, 0] _tp = cm[1, 1] _tpr = _tp / (_tp + _fn) _fpr = _fp / (_fp + _tn) print(_fpr, _tpr) # 输出结果和roc_curve返回的中间值完全一致:0.6388888888888888 0.5433070866141733
如果你的业务场景中需要将False作为正类,只需要在调用roc_curve和confusion_matrix时显式传入参数pos_label=False,两个接口的计算结果就会和你最初手动计算的数值对齐。
内容的提问来源于stack exchange,提问作者teriyaki.sub47
相关产品推荐
相关产品推荐

