此代码返回并根据预测值和真实值绘制真实阳性率,错误阳性率,真实阳性计数,错误阳性计数:
def get_all_stats(y_true , y_pred) :
def perf_measure(y_true, y_pred):
TP = 0
FP = 0
TN = 0
FN = 0
for i in range(len(y_true)):
if y_true[i] == 1 and y_pred[i] == 1:
TP += 1
if y_pred[i]==1 and y_true[i]!=y_pred[i]:
FP += 1
if y_true[i]== 0 and y_pred[i]==0:
TN += 1
if y_pred[i]==0 and y_true[i] != y_pred[i]:
FN += 1
if(FP == 0) :
FPR = 0;
else :
FPR = FP / (FP + TN)
if(TP == 0) :
TPR = 0
else :
TPR = TP / (TP + FN)
return(TN , FPR, FN , TPR , TP , FP)
tn, fpr, fn, tpr, tp , fp = perf_measure(y_true, y_pred)
return tpr , fpr , tp , fp
tpr1 , fpr1 , tp1 , fp1 = get_all_stats(y_true=[1,1,1] , y_pred=[1,0,0])
tpr2 , fpr2 , tp2 , fp2 = get_all_stats(y_true=[1,0,1] , y_pred=[0,1,0])
tpr3 , fpr3 , tp3 , fp3 = get_all_stats(y_true=[0,0,0] , y_pred=[1,0,0])
plt.figure(figsize=(12,6))
plt.tick_params(labelsize=12)
print(tpr1 , fpr1 , tp1 , fp1)
print(tpr2 , fpr2 , tp2 , fp2)
print(tpr3 , fpr3 , tp3 , fp3)
plt.plot([fpr1,fpr2,fpr3], [tpr1 , tpr2, tpr3], color='blue', label='')
plt.ylabel("TPR",fontsize=16)
plt.xlabel("FPR",fontsize=16)
plt.legend()
生成的结果ROC图为:
为了模拟三种不同的假阳性率和真阳性率,并且不同的阈值通过使用不同的函数三次实现get_all_stats
来计算这些值
tpr1 , fpr1 , tp1 , fp1 = get_all_stats(y_true=[1,1,1] , y_pred=[1,0,0])
tpr2 , fpr2 , tp2 , fp2 = get_all_stats(y_true=[1,0,1] , y_pred=[0,1,0])
tpr3 , fpr3 , tp3 , fp3 = get_all_stats(y_true=[0,0,0] , y_pred=[1,0,0])
有9个实例的真实值分别为1或0:[1,1,1,1,0,1,0,0,0]
在阈值1处,预测值为[1,0,0]
,而在此阈值处的真实值为[1,1,1]
。
在阈值2处,预测值为[0,1,0]
,而在此阈值处的真实值为[1,0,1]
。
在阈值3处,预测值为[1,0,0]
,而在此阈值处的真实值为[0,0,0]
。
可以看到,生成的分类器图与“典型” ROC曲线不同:
当它首先下降时,假阳性率和真阳性率降低,从而导致线“向后移动”。我是否正确实施了ROC曲线?可以为该曲线计算AUC吗?
答案 0 :(得分:2)
好的,因为您有很多代表,所以很乐于提供帮助->帮助了很多其他人。我们走了。
此ROC曲线没有意义。问题在于,您仅在不同阈值的数据子集上计算FPR / TPR。在每个阈值处,您应该使用所有数据全部来计算FPR和TPR。因此,您的绘图中似乎有3点,但是对于y_true = [1,1,1,1,0,1,0,0,0]
和y_pred = [1,0,0,0,1,0,1,0,0]
,您在FPR / TPR中只应得到1点。但是,为了确保您具有实际的ROC曲线,您也不能只在不同的阈值处组成y_pred
值-这些值必须来自实际的预测概率,然后将其适当地阈值化。我有点修改了您的代码,因为我喜欢使用numpy
;这是计算ROC曲线的方法。
# start with the true labels, as you did
y_true = np.array([1, 1, 1, 1, 0, 1, 0, 0, 0])
# and a predicted probability of each being a "1"
# I just used random numbers for these, but you would get them
# from your classifier
predictions = np.array([
0.07485627, 0.72546085, 0.60287482,
0.90537829, 0.75789236, 0.01852192,
0.85425979, 0.36881312, 0.63893516
])
# now define a set of thresholds (the more thresholds, the better
# the curve will look). There's a smarter way to do this in practice
# (you can sort the predicted probabilities and just have one threshold
# between each), but this is just to help with understanding
thresholds = np.linspace(0, 1, 11) # 0.1, 0.2, ..., 1.0
fprs = []
tprs = []
# we can precompute which inputs are actually 1s/0s and how many of each
true_1_idx = np.where(y_true == 1)[0]
true_0_idx = np.where(y_true == 0)[0]
n_true_1 = len(true_1_idx)
n_true_0 = len(true_0_idx)
for threshold in thresholds:
# now, for each threshold, we use that on the underlying probabilities
# to get the actual predicted classes
pred_classes = predictions >= threshold
# and compute FPR/TPR from those
tprs.append((pred_classes[true_1_idx] == 1).sum() / n_true_1)
fprs.append((pred_classes[true_0_idx] == 1).sum() / n_true_0)
plt.figure(figsize=(12,6))
plt.tick_params(labelsize=12)
plt.plot(fprs, tprs, color='blue')
plt.ylabel("TPR",fontsize=16)
plt.xlabel("FPR",fontsize=16)
请注意,随着FPR(x轴)的增加,ROC曲线在TPR(y轴)中始终不会减少;也就是说,当您向右移动时,它会上升。从阈值的工作原理可以清楚地看出。在阈值0时,所有预测均为“ 1”,因此我们的FPR = TPR =1。增大阈值将得到较少的预测“ 1”,因此FPR和TPR只能保持不变或减小。
请注意,即使我们使用最佳阈值,由于我们有有限的数据量,曲线上仍然会有跳跃,因此我们可以通过任何阈值获得有限数量的不同TPR / FPR对。但是,如果您有足够的数据,那么看起来就很平滑。在这里,我在上面的代码中替换了几行以得到更平滑的图:
n_points = 1000
y_true = np.random.randint(0, 2, size=n_points)
predictions = np.random.random(n_points)
thresholds = np.linspace(0, 1, 1000)
如果不清楚,则AUC为0.5可能是最坏的情况,您可以看到这就是我们通过随机“预测”得到的结果。如果您的AUC小于0.5,则可以将每个预测都大于0.5(并且您的模型/训练可能有问题)。
如果您实际上想在实践中绘制ROC曲线,而不仅仅是自己写一点,以学习更多,请使用sklearn的roc_curve
。他们也有roc_auc_score
为您获得AUC。