本文详细讨论了分类模型的常用评价指标,包括准确率、平均准确率、混淆矩阵、精确率、召回率、F1值和AUC等。对这些指标含义的理解和运用,尤其是在不平衡样本数据集上的应用,是设计恰当模型和指导AI大模型调整模型需要掌握的知识。对这些指标的讨论采用了示例入手、逐步推进的方式,便于读者理解。
在本专栏的前述文章里,对分类模型的评价采用了最简单的准确率。本文详细讨论分类模型的常用评价指标。无论是自己设计模型,还是指导AI大模型去调整模型,评价指标显然是必须理解的内容。
本文仍然采用示例入手的分析方法,便于读者理解。读者也可暂时跳过公式推导部分,先掌握应用方法。
6 AUC(Area under the Curve)
在样本类别分布不平衡带来的评价问题上,AUC有很好的评价效果。AUC的全称是Area under the Curve,即曲线下的面积,这条曲线便是ROC曲线,它的全称为the Receiver Operating Characteristic曲线,直译过来为:受试者工作曲线。在上世纪50年代的电信号分析中最开始使用。ROC曲线有一个重要特性:当测试集中正负样本的分布发生变化时,该曲线能够保持不变。
ROC是以假正率FPR为横坐标,以真正率TPR为纵坐标的一条曲线,FPR和TPR的取值范围都是[0,1],ROC曲线示例如图9-1所示。
图9-1 ROC曲线示例
ROC曲线的含义是什么呢?
先来看一条特殊的曲线。图9-1中,Random是一条连接原点到点(1,1)的直线,Random上的点的模坐标与纵坐标相等,也就是说FPR与TPR相等,不妨以Random上的点c(0.5,0.5)为例来看看该直线的含义。如果点c表示某个模型的预测能力,那么,该模型的假正率FPR和真正率TPR都为0.5,这意味着该模型对样本的预测类似于抛硬币,不管样本的特征是什么,随机等概打上正负标签即可。再来看Random上的点e(0.25,0.25),它表示的模型则是对样本的预测类似掷一个四面的骰子,随机掷出指定的一面,则为正类,否则为负类,也就是说,该模型是按0.25的概率来随机给样本打正标签。因此,Random直线表示的模型是以一定概率来进行随机预测,原点表示所有的样本都按概率0判断为正类,点(1,1)表示所有的样本都按概率1判断为正类。这样的模型并没有什么实际意义。
再看Random上方的点,以点c正上方的b为例。点b表示的模型在真正率TPR上有了提高,不再是随机打标签了,提高了对正类实例的预测能力。而对于Random下方的点,表示预测能力比随机猜测还要差,这并没有讨论的意义。因此,只有位于Random上方的点代表的模型才具有实际的分类能力。像点a这样TPR为1的点代表的模型对正类样本的预测能力达到了完美,即能够全部预测出来。而FPR为0的点代表的模型对负类样本的预测能力达到了完美。它们的交叉点(0,1)代表的模型对正负两类样本都能够全部正确预测出来,是最完美的模型。因此,要尽量使模型靠近点(0,1),即要同时使FPR趋近于0和使TPR趋近于1。
但是,对于一个分类模型来说,它的FPR和TPR是有关联的,并不能在使一个指标改善的同时也使另一个得到改善。分类模型的FPR和TPR的关联性如图9-1中的ROC曲线所示,提高一个指标同时会降低另一个指标。
如何得到ROC曲线呢?
从概率论的角度来看,模型关于每个样本的预测都存在一个概率值,好的模型就是要将原本为正类的样本判定为正的概率尽量大,而原本为负类的样本判定为正的概率尽量小。不同的模型学到的知识不同(提取的特征、采用的算法等因素影响),关于每个样本的预测概率也不同。模型对样本进行预测的概率分布如图9-2所示意。
图9-2 二分类模型对样本进行预测的概率分布示意图
图9-2中,横坐标表示某模型将样本预测为正的概率,纵坐标表示样本数量,正类曲线上的点(x,y)表示有y个正样本会以x大小的概率被预测为正样本,负类曲线上的点(x,y)表示有y个负样本会以x大小的概率被预测为正样本。如果对概率设定一个阈值,当大于该阈值的样本判定为正(图中阈值右边部分),那么随着阈值的变化判定为正的样本数量也会变化。对正类曲线来说,阈值右边部分(横线阴影部分)的面积是所有判定为正的正样本的数量,即TP。对负类曲线来说,阈值右边部分(斜线阴影部分)的面积是所有判定为正的负样本的数量,即FP。从图中可以看出,随着阈值的变化,TP和FP会同时变大,或者同时变小,这正是FPR和TPR不能同时得到改善的原因。
当阈值从1取到0时,可以得到一系列FP与TP值,并除以所有正类样本数量和负类样本数量,从而得到一系列FPR和TPR值对,它们的变化范围是从0到1。以FPR为横坐标值,以TPR为纵坐标值,将这些FPR和TPR值对作点画出来,就得到了图9-1中的ROC曲线。对于图9-1中的c点和(0,1)点代表的分类模型如图9-3中左、右两图所示。
图9-3 二分类模型对样本预测概率分布的特殊情况
好的分类模型是尽量使图9-2中正类曲线和负类曲线离得远的模型,它的ROC曲线也会更接近(0,1)点。图9-1中,ROC’曲线代表的模型比ROC曲线代表的模型就要更好一点,此时,该曲线下的面积就要更大,即AUC更大。
因为ROC曲线的坐标轴采用的是样本的比例值,因此即使正负样本的类别分布发生变化,ROC曲线也会保持不变,也就是说,AUC不会受样本分类不平衡的影响。因此AUC常用来评价类别不平衡的模型。
如何来实际计算AUC值呢?
首先分类模型要能给出每个样本的预测概率,这可以通过在神经网络的最后一层采用softmax等激活函数来实现。然后,统计出每个概率值的正类和负类样本数量,得到如图9-2所示的样本概率分布(实际应用中,概率值不是连续的,得到的正类曲线和负类曲线也不是连续的)。
根据样本概率分布,将阈值从1取到0,由得到的FPR和TPR值对作点画出ROC曲线,当然,实际应用中的ROC曲线不是一条连续的平滑曲线,而是一条锯齿状的ROC曲线(如图9-4中右图所示),计算该曲线下的面积即为AUC值。
图9-4 预测概率分布和ROC曲线示例
来看一个示例。假设有19个样本,它们的标签和模型的预测概率值如下:
标签:0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1;
预测概率值:0.1,0.2,0.2,0.3,0.3,0.4,0.5,0.7,0.9,0.15,0.45,0.55,0.75,0.75,0.85,0.95,0.75,0.85,0.95。
画出它们的概率分布图如图9-4左图所示,图中细线表示负类样本的数量,粗线表示正类样本的数量。利用sklearn.metrics包中的roc_curve()函数计算出各点的fpr和tpr对,将它们代表的点依次连上,画出ROC曲线如图9-4右图所示。实现以上过程的代码见代码9-2。
代码9-2 AUC示例
importpandasaspdimportmatplotlib.pyplotasplt##### 样本的标签值和预测概率data={'label':[0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1],'proba':[0.1,0.2,0.2,0.3,0.3,0.4,0.5,0.7,0.9,0.15,0.45,0.55,0.75,0.75,0.85,0.95,0.75,0.85,0.95]}df=pd.DataFrame(data)len(df)#>>> 19##### 画出概率分布图group=df.groupby(['label','proba'])# 按标签值和概率值分组la0=group.size()[0]# 负类样本概率值统计数la1=group.size()[1]# 正类样本概率值统计数x0=[]# 负类样本概率值y0=[]# 负类样本概率值对应的样本数量forindex,valinla0.items():x0.append(index)y0.append(val)x1=[]y1=[]forindex,valinla1.items():x1.append(index)y1.append(val)plt.rcParams['font.sans-serif']=['SimHei']# 设置字体为黑体plt.rcParams['axes.unicode_minus']=Falsep1=plt.bar(x0,height=y0,width=0.005)# 细线表示负类样本分布p2=plt.bar(x1,height=y1,width=0.02)# 组线表示正类样本分布plt.xlabel('预测概率值',size=18)plt.ylabel('样本数量',size=18)plt.title('预测概率分布',size=18)#>>> Text(0.5, 1.0, '预测概率分布')
##### 计算FPR和TPR对,并画出ROC曲线fromsklearnimportmetrics fpr,tpr,thresholds=metrics.roc_curve(df['label'].values,df['proba'].values,pos_label=1)plt.plot(fpr,tpr,marker='o')plt.xlabel('False Positive Rate',size=18)plt.ylabel('True Positive Rate',size=18)plt.title('ROC Curve',size=18)#>>> Text(0.5, 1.0, 'ROC Curve')
print("auc = "+str(metrics.auc(fpr,tpr)))# metrics.auc函数是以梯形法则求出ROC曲线与横坐标所夹面积#>>> auc = 0.8
来验证一下ROC曲线。
当阈值大于0.95时,统计可知FP为0 、TP为0,因此FPR和TPR分别也为0,对应图中左侧第1个点。
当阈值等于0.95时,统计可知FP为0 、TP为2,再除以负类样本总数和正类样本总数,得到FPR和TPR分别为0和0.2,对应图中第2个点。
当阈值等于0.9时,统计可知FP为1、TP为2,计算得到得到FPR和TPR分别为0.11和0.2,对应图中第3个点。
如此,可验证全部ROC曲线上的点。
sklearn.metrics包提供了直接计算AUC的函数auc(),它是以梯形法则求出ROC曲线下的面积,计算得到示例中的AUC值为0.8。
计算本文示例的AUC值的代码见代码9-1.5。
代码9-1.5 计算AUC值
### 10. 计算AUC值print('ROC曲线和AUC值:')print('-'*40)# 使用sklearn的roc_auc_scoreauc_score=metrics.roc_auc_score(all_labels,all_probabilities)print(f"AUC值 (sklearn):{auc_score:.4f}")# 使用sklearn的roc_curvefpr,tpr,thresholds=metrics.roc_curve(all_labels,all_probabilities)# 可视化ROC曲线plt.figure(figsize=(8,6))plt.plot(fpr,tpr,color='darkorange',lw=2,label=f'ROC曲线 (AUC ={auc_score:.4f})')plt.plot([0,1],[0,1],color='navy',lw=2,linestyle='--',label='随机猜测')plt.xlim([0.0,1.0])plt.ylim([0.0,1.05])plt.xlabel('假正率 (False Positive Rate)')plt.ylabel('真正率 (True Positive Rate)')plt.title('受试者工作曲线 (ROC Curve)')plt.legend(loc="lower right")plt.grid(True,alpha=0.3)plt.tight_layout()plt.show()输出:
ROC曲线和AUC值: ---------------------------------------- AUC值 (sklearn): 0.9983