全文共15000余字,预计阅读时间约30~50分钟 | 满满干货,建议收藏!
一、引言
1.1 什么是分类模型
分类模型是机器学习的一种类型,它的任务是通过学习样本的特征来预测样本的类别。
分类模型通常用于那些输出变量是分类或者离散值的任务,例如,判断一封邮件是垃圾邮件还是非垃圾邮件,或者预测一个患者是否患有某种疾病。在训练过程中,分类模型会从标记好的训练数据中学习到如何判断一个样本属于哪个类别,然后在面对新的数据时,根据学习到的知识进行预测。
1.2 为什么要评估分类模型
评估分类模型的性能非常重要,因为它能帮助我们了解模型的表现如何,以及模型在实际应用中的可能表现。通过使用不同的评估指标,可以从不同的角度理解模型的性能。
作为使用场景最为广泛的机器学习模型,其评估指标也随着使用场景的拓展而不断丰富,例如,可以通过查看模型的准确率来了解模型正确预测的比例,还有**精确度、召回率、F1分数、受试者特征曲线(ROC-AUC)**等,不同评估指标有对应的不同的计算方法,同时也对应着不同的使用场景。
本文就详细介绍这几种分类模型的评估指标,让您一文搞懂!
在开始之前,先搞懂四个概念:
- “真正例”(True Positive,TP)是指模型预测为正,实际上也是正的情况,例如,模型预测一个人有疾病,实际上这个人确实有疾病。
- “假正例”(False Positive,FP)是指模型预测为正,但实际上是负的情况,例如,模型预测一个人有疾病,但实际上这个人是健康的。
- “真负例”(True Negative,TN)是指模型预测为负,实际上也是负的情况,例如,模型预测一个人没有疾病,实际上这个人确实没有疾病。
- “假负例”(False Negative,FN)是指模型预测为负,但实际上是正的情况,例如,模型预测一个人没有疾病,但实际上这个人是有疾病的。
二、准确率(Accuracy)
2.1 准确率的定义
准确率,或者叫准确度,是用来评价分类模型性能的一种基本指标。它的基本含义是模型预测正确的样本数占总样本数的比例。也就是说,它表示的是模型做出正确预测的概率。通过以下公式计算的:
准确度 ( A c c u r a c y ) = 真正例 ( T P ) + 真负例 ( T N ) 真正例 ( T P ) + 假正例 ( F P ) + 真负例 ( T N ) + 假负例 ( F N ) (1) \text 准确度(Accuracy) = \frac {真正例(TP) + 真负例(TN)} {真正例(TP) + 假正例(FP) + 真负例(TN) + 假负例(FN)} \tag{1} 准确度(Accuracy)=真正例(TP)+假正例(FP)+真负例(TN)+假负例(FN)真正例(TP)+真负例(TN)(1)
举个例子来理解一下,假设有如下数据:
预测类别 | 实际类别 |
---|---|
A | A |
B | A |
A | A |
B | B |
B | B |
在上述数据中,模型进行了5个样本的预测,可以计算准确率思路如下:
-
计算预测正确的样本数。在表格中,第1行、第3行和第5行的预测类别与实际类别相同,因此共有3个预测正确的样本。
-
计算总样本数。根据表格中的数据,共有5个样本进行了预测。
-
将预测正确的样本数除以总样本数,即可计算准确率,即:
准确率 = 预测正确的样本数 总样本数 = 3 5 = 0.6 = 60 % (2) 准确率 = \frac {预测正确的样本数} {总样本数} = \frac{3} {5} = 0.6 = 60\% \tag{2} 准确率=总样本数预测正确的样本数=53=0.6=60%(2)
因此,在这个示例中,准确率为60%。
2.2 准确率的局限性(重要)
准确率是一种非常直观的评估指标,可以快速地告诉反映出模型预测正确的概率有多高。然而,它存在一些局限性,整体来看:
1. 对不平衡数据的敏感性:准确率在计算过程中,所有样本其实是“均匀投票”的,也就是说对每个样本的判别结果,对于最终准确率的影响其实是相同的。如果数据集不平衡,也就是说某一类别的样本数远大于其他类别,那么准确度就可能无法反映出模型的真实性能。例如,在一个有100个样本的数据集中,有95个正例和5个负例,一个总是预测为正例的模型可以得到95%的准确度,但是这个模型对负例的预测能力其实是非常差的。
2. 没有考虑到假正例和假负例:准确度并没有考虑到假正例(被错误预测为正例)和假负例(被错误预测为负例)。将0错判为1、和将1错判为0,其实实际付出的代价是不一样的,很多时候我们并不是单纯的追求将所有的0样本都正确的识别为0且将1样本都正确的判别为1,特别是在某些场景下,假正例和假负例的成本可能会非常高。例如,在疾病预测中,假负例(将患病的人预测为健康)可能会带来严重的后果。
关于准确率的第三方面局限,实际上是一个相对隐藏更深的问题,那就是对于哪怕是均衡的分类样本数据集,准确率有时也无法很好的衡量分类模型的分类性能、尤其是模型本身的泛化能力,这也是为什么不以准确率而以交叉熵作为损失函数的另一个原因。
例如,假设对下述5条样本的二分类数据集,构建A、B两个逻辑回归模型进行判别,模型判结果如下所示:
如果从准确率指标考虑,观察上表中的两个模型(模型A和模型B),会发现当设定阈值为0.5时,这两个模型的准确率均为80%(仅第二条样本被误判)。这意味着,从准确率的角度看,二者似乎没有优劣之分。
然而,如果深入地研究模型对各样本的概率预测结果,会发现模型A实际上更为“优秀”。首先,对于模型正确分类的正例数据,模型A的概率预测结果为0.8、0.9和0.9,这意味着模型A高度肯定这些样本属于正例。相反,模型B的概率预测结果为0.6、0.7和0.6,这表示模型B对这些样本是否属于正例的确信度较低。这种趋势也在两个模型正确识别负例的过程中得到体现。
其次,对于被误判的样本,尽管两个模型都将实际为负例的第二条样本误判为正例,但模型B的预测概率达到了0.9,显示它高度肯定该样本属于正例。而模型A的预测概率为0.6,说明它并不过于确信该样本为正例。
在实际的模型建立过程中,像模型A这样对判断正确的样本有较高的确信度,对判断错误的样本表现出适当犹豫的模型,通常能更准确地捕捉到数据的规律。当它们应用于新的数据集预测时,也能表现出更强的泛化能力。然而,遗憾的是,准确率评估指标并不能有效地区分像模型A和模型B这样的模型判别能力。
此时通过交叉熵来比较两个模型的好坏优劣。
交叉熵计算结果越小、模型本身判别能力越强,借助交叉熵计算公式来计算两个模型输出结果的交叉熵:
B
C
E
A
=
−
l
o
g
2
(
0.8
)
−
l
o
g
2
(
0.4
)
−
l
o
g
2
(
−
0.8
)
−
l
o
g
2
(
0.9
)
−
l
o
g
2
(
0.9
)
5
=
0.31
(3)
BCE_A = \frac{-log_2(0.8)-log_2(0.4)-log_2(-0.8)-log_2(0.9)-log_2(0.9)}{5} = 0.31 \tag{3}
BCEA=5−log2(0.8)−log2(0.4)−log2(−0.8)−log2(0.9)−log2(0.9)=0.31(3)
B C E B = − l o g 2 ( 0.6 ) − l o g 2 ( 0.1 ) − l o g 2 ( − 0.6 ) − l o g 2 ( 0.7 ) − l o g 2 ( 0.6 ) 5 = 0.83 (4) BCE_B = \frac{-log_2(0.6)-log_2(0.1)-log_2(-0.6)-log_2(0.7)-log_2(0.6)}{5}=0.83 \tag{4} BCEB=5−log2(0.6)−log2(0.1)−log2(−0.6)−log2(0.7)−log2(0.6)=0.83(4)
能够看出,模型A输出结果的交叉熵是要小于模型B的,因此模型A其实拥有对既定样本更强的判别能力。无论是从通俗的角度看模型对样本类别判别的肯定程度,还是从交叉熵计算结果来看,模型A、B实际上是存在判别能力的差异的,但这种差异无法被准确率很好的衡量。
三、精确度 (Precision)
3.1 精确度的定义
精确度,也称为查准率,是分类模型评估指标之一,主要用于评估模型对正例的预测准确性。
精确度更加关注每一次出手(对1类样本的识别)能否成功(准确识别出1)的概率
它的基本含义是模型预测为正例的样本中,实际也为正例的比例。通过以下公式计算:
精确度 ( P r e c i s i o n ) = 真正例 ( T P ) 真正例 ( T P ) + 假正例 ( F P ) (3) \text 精确度(Precision)=\frac {真正例(TP)} {真正例(TP) + 假正例(FP)}\tag{3} 精确度(Precision)=真正例(TP)+假正例(FP)真正例(TP)(3)
其中,真正例(TP)是指模型正确预测为正例的样本数,假正例(FP)是模型错误预测为正例的样本数。
举个例子来理解一下,假设有如下数据:
预测类别 | 实际类别 |
---|---|
A | A |
B | A |
A | A |
B | B |
B | B |
想要计算预测类别A(把它视为正例)的精确度,计算步骤如下:
-
计算真正例数(TP)。在表格中,第1行和第3行的预测类别和实际类别都是A,因此共有2个真正例。
-
计算假正例数(FP)。在表格中,只有第2行的预测类别是A,但实际类别是B,因此有1个假正例。
-
将真正例数除以真正例数和假正例数之和,即可计算精确度,即:
精确度 ( P r e c i s i o n ) = 真正例数 真正例数 + 假正例数 = 2 2 + 1 = 0.67 = 67 % (4) \text{精确度}(Precision) = \frac{\text{真正例数}}{\text{真正例数 + 假正例数}} = \frac{2}{2 + 1} = 0.67 = 67\% \tag{4} 精确度(Precision)=真正例数 + 假正例数真正例数=2+12=0.67=67%(4)
因此,在这个示例中,精确度为67%。
3.2 精确度的局限性
1. 忽视了假负例的影响:精确度只考虑了假正例,而忽视了假负例(被错误预测为负例)的存在。如果关心的是将所有正例都预测出来,而不仅仅是预测为正例的样本中有多少是真正的正例,那么精确度就可能无法满足我们的需求。
2. 对不平衡数据的敏感性:如果数据集中负例远多于正例,即使模型将所有的正例都预测正确,由于假正例的数量很小,精确度依然可能很高。但是这种情况下,模型对负例的预测能力可能很差。
因此,通常会结合召回率一起使用,以便从不同的角度评估模型的性能。
四、召回率(Recall)
4.1 召回率的定义
召回率,也称为查全率或者敏感性,是分类模型评估指标之一,主要用于评估模型对正例的覆盖能力。
召回率侧重于关注全部的1类样本中别准确识别出来的比例。
它的基本含义是实际为正例的样本中,模型预测为正例的比例。通过以下公式计算:
召回率(Recall) = 真正例(TP) 真正例(TP) + 假负例(FN) (5) \text{召回率(Recall)} = \frac{\text{真正例(TP)}}{\text{真正例(TP) + 假负例(FN)}} \tag{5} 召回率(Recall)=真正例(TP) + 假负例(FN)真正例(TP)(5)
其中,真正例(TP)是指模型正确预测为正例的样本数,假负例(FN)是模型错误预测为负例的样本数。
举个例子来理解一下,假设有如下数据:
预测类别 | 实际类别 |
---|---|
A | A |
B | A |
A | A |
B | B |
B | B |
想要计算实际类别A(把它视为正例)的召回率,计算步骤如下:
-
计算真正例数(TP)。在表格中,第1行和第3行的预测类别和实际类别都是A,因此共有2个真正例。
-
计算假负例数(FN)。在表格中,只有第2行的预测类别是B,但实际类别是A,因此有1个假负例。
-
将真正例数除以真正例数和假负例数之和,即可计算召回率,即:
召回率 = 真正例数 真正例数 + 假负例数 = 2 2 + 1 = 0.67 = 67 % (6) \text{召回率} = \frac{\text{真正例数}}{\text{真正例数 + 假负例数}} = \frac{2}{2 + 1} = 0.67 = 67\% \tag{6} 召回率=真正例数 + 假负例数真正例数=2+12=0.67=67%(6)
因此,在这个示例中,召回率为67%。
4.2 召回率的局限性
-
忽视了假正例的影响:召回率只考虑了假负例,而忽视了假正例(被错误预测为正例)的存在。如果关心的是将所有预测为正例的样本都预测正确,而不仅仅是将所有的正例都预测出来,那么召回率就可能无法满足需求。
-
对不平衡数据的敏感性:如果数据集中正例远多于负例,即使模型将所有的负例都预测正确,由于假负例的数量很小,召回率依然可能很高。但是这种情况下,模型对正例的预测能力可能很差。
如果以召回率作为模型评估指标,则会使得模型非常重视是否把1全部识别了出来,甚至是牺牲掉一些0类样本判别的准确率来提升召回率,即哪怕是错判一些0样本为1类样本,也要将1类样本识别出来,这是一种“宁可错杀一千不可放过一个”的判别思路。因此,召回率其实是一种较为激进的识别1类样本的评估指标,在0类样本被误判代价较低、而1类样本被误判成本较高时可以考虑使用。“宁可错杀一千不可放过一个”
因此,通常会结合精确度一起使用,以便从不同的角度评估模型的性能。通过精确度和召回率,可以计算出F1分数,以平衡这两个指标。
五、F1 分数 (F1 Score)
很明显,召回率和精确度是一对相对的概念,它们在关注正类样本的识别过程中,各有侧重点。召回率的目标是尽可能地将正类样本识别出来,而精确度则追求在每次对正类样本的判断都能获得正确的结果。
然而,在大多数情况下,我们的期望是获得一个在两者之间实现“均衡”的模型评估指标,既不希望模型过于冒进,也不希望模型过于保守。特别是对于偏斜的样本,不仅要求模型能够准确地识别出正类样本,同时也希望能尽可能地减小对负类样本准确率的牺牲。因此,在这种情况下,可以考虑使用召回率和精确度的调和平均数作为模型评估指标,这就是F1-Score。
F 1 − S c o r e = 2 1 R e c a l l + 1 P r e c i s i o n = 2 ⋅ R e c a l l ⋅ P r e c i s i o n R e c a l l + P r e c i s i o n (7) \text F1-Score = \frac{2}{\frac{1}{Recall}+\frac{1}{Precision}}=\frac{2 \cdot Recall \cdot Precision}{Recall+Precision} \tag{7} F1−Score=Recall1+Precision12=Recall+Precision2⋅Recall⋅Precision(7)
即:
F 1 − S c o r e = 2 ⋅ T P 2 ⋅ T P + F P + F N (8) F1-Score = \frac{2\cdot TP}{2\cdot TP+FP+FN} \tag{8} F1−Score=2⋅TP+FP+FN2⋅TP(8)
F1-Score是一个介于[0,1]之间的计算结果,当FP+FN=0时候(即没有误判样本时),F1-Score计算结果为1;而当没有正确识别出一个1时,即TP=0时,F1-Score=0。
假设有如下数据:
预测类别 | 实际类别 |
---|---|
正类 | 正类 |
负类 | 正类 |
正类 | 正类 |
负类 | 负类 |
负类 | 负类 |
在上述数据中,模型预测了5个样本,预测结果如上表所示。先根据这个结果计算精确度和召回率:
- 计算精确度。在表格中,第1行和第3行的预测类别与实际类别相同,因此有2个正例预测正确。预测为正例的样本共有2个(第1行和第3行)。因此,精确度可以计算为:
精确度 = 预测正确的正例数 预测为正例的样本数 = 2 2 = 1 (9) 精确度 = \frac {预测正确的正例数} {预测为正例的样本数} = \frac {2} {2} = 1 \tag{9} 精确度=预测为正例的样本数预测正确的正例数=22=1(9)
- 计算召回率。实际为正例的样本共有3个(第1行、第2行和第3行),其中有2个被正确预测为正例。因此,召回率可以计算为:
召回率 = 预测正确的正例数 实际为正例的样本数 = 2 3 ≈ 0.67 (10) 召回率 = \frac {预测正确的正例数} {实际为正例的样本数} = \frac{2} {3} ≈ 0.67 \tag{10} 召回率=实际为正例的样本数预测正确的正例数=32≈0.67(10)
然后,可以根据公式计算F1分数:
F 1 = 2 ∗ 精确度 ∗ 召回率 精确度 + 召回率 = 2 ∗ 1 ∗ 0.67 1 + 0.67 ≈ 0.80 (11) F1 = 2 * \frac {精确度 * 召回率} {精确度 + 召回率} = 2 * \frac {1 * 0.67} {1 + 0.67} ≈ 0.80 \tag{11} F1=2∗精确度+召回率精确度∗召回率=2∗1+0.671∗0.67≈0.80(11)
所以,根据这个例子,可以得到F1分数约等于0.80。
六、混淆矩阵 (Confusion Matrix)
混淆矩阵提供了一种直观的方式来理解模型的表现,能够清晰地看到模型在各个类别上的预测性能,而不仅仅是一个总的准确度指标。同时,它也是计算许多其他重要性能指标的基础。
- TP(True Positive):真正例,即实际上是正例,预测也为正例。
- FN(False Negative):假负例,即实际上是正例,预测为负例。
- FP(False Positive):假正例,即实际上是负例,预测为正例。
- TN(True Negative):真负例,即实际上是负例,预测也为负例。
上面提到的准确率、精确率和召回率都可以从混淆矩阵中计算得出:
在这个混淆矩阵中,样本总数 = P + N,其中:
- P: 实际为正类的样本数量(Actual condition positive)。
- N: 实际为负类的样本数量(Actual condition negative)。
在预测结果中:
- Predicted condition positive (PP): 预测为正类的样本数量。
- Predicted condition negative (PN): 预测为负类的样本数量。
总的来说,准确率、召回率、精确度和F1-score都是评估模型性能的重要指标,而混淆矩阵则以直观的方式将这些指标融合在一起,提供了一种全面、详细的方式来理解和评估模型的分类性能。
在评估指标选取上,需要根据实际情况判断,如果只需要考虑正类别的识别率,则可考虑使用Recall作为模型评估指标,若只需考虑对正类样本判别结果中的准确率,则可考虑使用Precision作为评估指标。但一般来说这两种情况其实都不多,更普遍的情况是,需要重点识别正类但也要兼顾负类的准确率,此时可以使用F1-Score指标。F1-Score其实也是分类模型中最为通用和常见的分类指标。
七、ROC曲线和AUC值
7.1 特异度和阴性预测值
Recall和Precision其实都是围绕以识别正类为核心目标来构建的评估指标,由于二分类的两个类别的对称性,如果以识别负类为核心目标来构建一套模型评估指标,那么就是特异度和阴性预测值
特异度Specificity:也叫真负率(True Negative Rate, TNR),它是正确预测为负类(True Negatives,TN)占所有实际负类的比例,即:
S
p
e
c
i
f
i
c
i
t
y
=
T
N
T
N
+
F
P
(12)
Specificity = \frac{TN}{TN+FP} \tag{12}
Specificity=TN+FPTN(12)
特异度关注的是所有实际为负类的样本中,被正确分类的比例。这和召回率是相反的,召回率关注的是所有实际为正类的样本中,被正确分类的比例。
阴性预测值(negative predictive value):也称为预测负类的精确度,它是正确预测为负类的样本数(TN)占所有预测为负类的样本数的比例(即 TN / (TN + FN))。即:
N P V = T N T N + F N (13) NPV = \frac{TN}{TN+FN} \tag{13} NPV=TN+FNTN(13)
阴性预测值关注的是预测为负类的样本中,实际也为负类的比例。这和精确度是相反的,精确度关注的是预测为正类的样本中,实际也为正类的比例。
召回率和精确度通常用于关注正类的预测表现,而特异度和阴性预测值则通常用于关注负类的预测表现。
7.2 什么是ROC曲线和AUC值
ROC曲线(Receiver Operating Characteristic curve)和AUC值(Area Under Curve)是一对一一对应的概念,用于评估分类模型的整体分类性能。ROC曲线在二维平面上呈现,而AUC值则是ROC曲线下的面积值,具有明确的数值特性。
ROC曲线和AUC值主要用于度量模型在处理正负样本时的表现,具有很强的直观性和解释性。横轴是假正率,纵轴是真正率,通过改变模型的阈值,可以得到一系列假正率和真正率,从而描绘出ROC曲线。提供了一个直观的方式来观察模型在不同阈值下的表现,同时AUC值也提供了一个量化的方式来评估模型的整体性能。
7.3 ROC曲线绘制方法与AUC值计算方法
首先来看:ROC曲线的绘制过程。假设逻辑回归对某一组数据分类结果如下,按照预测概率从大到小进行排序:
数据总共20条样本,11条1类样本、9条0类样本。
在阈值取值范围为0.9-1之间时,模型将判别所有样本都属于0类,对于上述数据集来说,有混淆矩阵计算结果如下:
此时,令FDR为平面坐标的横坐标点、TPR作为平面坐标的纵坐标点,就可以绘制出ROC曲线上的第一个点:(0, 0)点。
然后,不断降低阈值,当阈值跨过0.9时,即介于0.8和0.9之间时,上述混淆矩阵计算结果将发生变化,此时模型将判别概率为0.9的样本为1类,其余样本为0类,此时上述混淆矩阵计算结果如下:
此时就计算出了ROC曲线上的第二个点:(0, 0.09)。
如果进一步降低阈值,当阈值移动到0.7和0.8之间时,模型判别结果又将发生变化,可以继续计算此时的TPR和FDR。在不断调整阈值的过程中,阈值每跨越一个样本的预测概率,FDR和TPR就会发生变化,最终,将阈值从1逐渐降低到0的过程中的所有计算结果放在数据表中进行观察:
当阈值完整从1移动0之后,即可把上述所有由(FPR,TPR)所组成的点绘制成一张折线图,该折线图就是ROC曲线图,直接上代码看一下:
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc
# 数据
y_true = [1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0] # True Class
y_scores = [0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.51, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.3, 0.1] # Predicted Probability
# 计算ROC
fpr, tpr, thresholds = roc_curve(y_true, y_scores)
roc_auc = auc(fpr, tpr)
# 绘制ROC曲线
plt.figure(figsize=(10, 6)) # 调整图形的大小
lw = 2
plt.plot(fpr, tpr, color='darkorange', lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic example')
# 绘制每个阈值的点
for i, thr in enumerate(thresholds):
plt.plot(fpr[i], tpr[i], marker='o', label='THR = {:.2f}'.format(thr))
# 将图例移到图的外面
plt.legend(loc="center left", bbox_to_anchor=(1, 0.5))
plt.show()
ROC曲线下方面积就是AUC值。
7.3 ROC-AUC的 基本性质
7.3.1 如何根据ROC-AUC判别模型
对于任意模型来说,ROC曲线越靠近左上方、ROC曲线下方面积越大,则模型分类性能越好。
根据点的移动轨迹构成ROC曲线角度来理解,刚开始移动时,是朝向X还是Y轴正向移动,其实是有模型输出概率最高的几个样本决定的,如果这几个样本被判别错了(即实际样本类别为0),则刚开始从原点移动就将朝着X轴正方向移动,此时曲线下方面积会相对更小(相比刚开始朝着Y轴正方向移动的情况),并且根据此前介绍的理论,此时由于模型对于“非常肯定”的样本都判错了,证明模型本身判别性能欠佳;而反之,如果输出概率最高的头部几条样本都判断正确,样本真实类别确实属于1,则点开始移动时将朝向Y轴正方向移动,此时曲线下方面积就将相对更大,模型判别性能也将相对较好。此处举例说明:
上述两个模型对于同一组数据的建模结果差异,可以简单看成模型A中概率结果为0.8和0.6的两条样本,在模型B中被识别为0.6和0.8,两条样本结果互换。
在0.5为阈值的情况下,模型A和B同样准确率是80%,但模型A是将概率为0.6的1类样本误判为0类、将概率为0.4的样本误判为1类,对于模型B来说,有一条概率结果为0.8的样本被误判,则说明模型B对于一条“非常肯定”属于1类的样本判断是错误的,B模型的“错误”更加“严重”,模型判别性能相对较弱,ROC曲线下方面积相对较小。可以在ROC曲线上能够进行非常清楚的展示,直接上代码:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 定义阈值取值范围
thr_l = np.linspace(1, 0, 100)
# 输入两个模型预测结果和数据真实标签
yhat_A = np.array([0.9, 0.8, 0.6, 0.4, 0.3]).reshape(-1, 1)
y_A = np.array([1, 1, 0, 1, 0]).reshape(-1, 1)
yhat_B = np.array([0.9, 0.8, 0.6, 0.4, 0.3]).reshape(-1, 1)
y_B = np.array([1, 0, 1, 1, 0]).reshape(-1, 1)
def logit_cla(yhat, thr=0.5):
"""
逻辑回归类别输出函数:
:param yhat: 模型输出结果
:param thr:阈值
:return ycla:类别判别结果
"""
ycla = np.zeros_like(yhat)
ycla[yhat >= thr] = 1
return ycla
# TPR计算过程
y_cla = logit_cla(yhat_A, thr=0.5)
P = y_cla[y_A == 1]
TPR = P.mean()
TPR
# FPR计算过程
N = y_cla[y_A == 0]
FPR = N.mean()
FPR
# 定义ROC曲线绘制函数
def ROC_curve(yhat, y, thr_l, label='ROC_curve'):
"""
ROC绘制曲线函数:
:param yhat: 模型输出的类别概率判别结果
:param y: 样本真实类别
:param thr_l:阈值取值列表
:param label:折线图的图例
:return :ROC曲线绘制图
"""
TPR_l = []
FPR_l = []
for i in thr_l:
y_cla = logit_cla(yhat, thr=i)
P = y_cla[y == 1]
TPR = P.mean()
TPR_l.append(TPR)
N = y_cla[y == 0]
FPR = N.mean()
FPR_l.append(FPR)
plt.plot(FPR_l, TPR_l, label=label)
# 绘制ROC曲线
ROC_curve(yhat_A, y_A, thr_l, label='Model A')
ROC_curve(yhat_B, y_B, thr_l, label='Model B')
plt.plot([0, 1], [0, 1], 'r--')
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('ROC_curve')
plt.legend(loc = 4)
模型A的ROC曲线整体更加趋于空间左上方,并且曲线下方面积更大,说明模型A实际判别性能更好。
7.3.2 概率敏感
概率敏感就是根据概率结果而非类别判别结果进行识别。
如果数据是偏态数据,ROC能够对模型对于偏态数据中少量样本的识别能力进行评估。例如,假设一个包含十条数据的小样本数据集,其中包含9条0类样本、1条1类样本,利用两个模型进行判别,模型判别结果如下所示:
对于这两个模型来说,在阈值为0.5的情况下,准确率都是60%,且F1-Score都是0.33.
但由于ROC是概率敏感的评估指标,对于不同的两个模型,只要在不同类别的概率计算结果分布上有所差异,最终ROC的绘制情况都会不同。对于上述两个模型来说,可以通过如下方式绘制两个不同模型的ROC曲线,直接上代码:
yhat = np.array([0.9, 0.8, 0.7, 0.6, 0.51, 0.4, 0.3, 0.2, 0.1, 0.01]).reshape(-1, 1)
y_A = np.eye(10)[:,1:2]
y_B = np.eye(10)[:,3:4]
ROC_curve(yhat, y_A, thr_l, label='Model A')
ROC_curve(yhat, y_B, thr_l, label='Model B')
plt.plot([0, 1], [0, 1], 'r--')
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('ROC_curve')
plt.legend(loc = 4)
从最终AUC面积来看,模型A效果好于模型B。而对概率敏感,也使得ROC在很多情况下具有比F1-Score更加敏感的模型性能的识别精度。并且从上述结果中能够看出,ROC和F1-Score类似,少数的1类样本的判别结果会很大程度影响AUC的计算结果,因此ROC-AUC也能用于判别模型在偏态样本上的分类能力。
7.3.3 排序敏感
ROC-AUC对根据模型预测的概率结果降序排序后的数据真实标签的各元素位置敏感,例如,对于下述A、B两个模型,尽管在部分样本的预测概率不同,但由于最终的按照预测概率降序排序的真实标签排序相同,因此两个模型最终绘制的ROC曲线相同。
# 定义阈值取值范围
thr_l = np.linspace(1, 0, 100)
# 输入两个模型预测结果和数据真实标签
yhat_A = np.array([0.9, 0.8, 0.56, 0.4, 0.3]).reshape(-1, 1)
y_A = np.array([1, 1, 0, 1, 0]).reshape(-1, 1)
yhat_B = np.array([0.7, 0.6, 0.56, 0.4, 0.3]).reshape(-1, 1)
y_B = np.array([1, 1, 0, 1, 0]).reshape(-1, 1)
# 绘制ROC曲线
ROC_curve(yhat_A, y_A, thr_l, label='Model A')
ROC_curve(yhat_B, y_B, thr_l, label='Model B')
plt.plot([0, 1], [0, 1], 'r--')
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('ROC_curve')
plt.legend(loc = 4)
7.4 类别对称性
所谓的"类别对称性",意味着改变哪个类别被标记为正类,对分类器的评估没有影响。例如,如果在做疾病检测,可以将"有疾病"定义为正例,"没有疾病"定义为负例,也可以反过来。在这两种情况下,分类器的性能(如ROC曲线)是不变的,这就是类别对称性。
F1-Score并不是类别对称的,它更加侧重于评估模型在识别1类样本时的整体性能,但ROC却是类别对称的,即如果将数据中的0和1类互换,而模型原先预测1的类概率就变成了现在预测0类的概率,此时ROC曲线会参照 x + y = 1 x+y=1 x+y=1的直线进行对称变换,但AUC面积不变,即模型性能评估数值仍然不会发生变化。
# 定义阈值取值范围
thr_l = np.linspace(1, 0, 100)
# 输入结果A
yhat_A = np.array([0.9, 0.8, 0.6, 0.4, 0.3]).reshape(-1, 1)
y_A = np.array([1, 1, 0, 1, 0]).reshape(-1, 1)
# 绘制ROC曲线
ROC_curve(yhat_A, y_A, thr_l, label='Result A')
plt.plot([0, 1], [0, 1], 'r--')
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('ROC_curve')
plt.legend(loc = 4)
# 输入结果B
yhat_B = np.array([0.7, 0.6, 0.4, 0.2, 0.1]).reshape(-1, 1)
y_B = np.array([1, 0, 1, 0, 0]).reshape(-1, 1)
# 绘制ROC曲线
ROC_curve(yhat_B, y_B, thr_l, label='Result B')
plt.plot([0, 1], [0, 1], 'r--')
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.title('ROC_curve')
plt.legend(loc = 4)
结合上述两组结果的FPR和TPR计算结果,二者的AUC计算结果都是 1 − 0.5 ∗ ( 1 − 0.66 ) = 0.83 1-0.5*(1-0.66)=0.83 1−0.5∗(1−0.66)=0.83,而这也正是由于两个ROC曲线围绕 x + y = 1 x+y=1 x+y=1对称所导致的。
因此,尽管同样是衡量模型整体评估性能,但相比之下,F1-Score更加倾向于判别模型对1类样本的识别能力,而ROC-AUC则没有这方面的倾向性。ROC-AUC和F1-Score之间的选取问题,同样也需要根据业务需要来进行选择,如果需要重点考虑1类是否被正确识别,则更加倾向选择F1-Score,但如果没有其他特殊要求,则一般会考虑使用ROC-AUC作为模型评估指标。
八、结语
本文全面探讨了分类模型的多种评估指标,包括准确率、精确度、召回率、F1分数,混淆矩阵,以及ROC曲线和AUC值。总的来说,我们应该注意,没有一个指标可以完美地评估所有任务。每一个指标都有其优点和局限,因此在实际操作中,我们需要根据具体问题来选择最合适的评估指标。这篇文章希望能为您在处理分类问题时提供一些参考,以更好地选择和评估模型。
最后,感谢您阅读这篇文章!如果您觉得有所收获,别忘了点赞、收藏并关注我,这是我持续创作的动力。您有任何问题或建议,都可以在评论区留言,我会尽力回答并接受您的反馈。如果您希望了解某个特定主题,也欢迎告诉我,我会乐于创作与之相关的文章。谢谢您的支持,期待与您共同成长!
期待与您在未来的学习中共同成长。