机器学习通用技术:混淆矩阵与ROC曲线
简介
在机器学习建模中,我们常常会用准确率,MSE等指标来衡量模型的优劣,但是在复杂的实际需求上,仅仅依靠这些指标是不够的,最典型的就是不平衡学习问题。这种问题往往是二分类问题,通常标签分布极不平衡,并且我们会重点关注其中一个类别的预测表现。例如,银行贷款问题,通常数据都是通过贷款的占大多数,并且我们重点关注未通过贷款的预测准确率,毕竟拒绝一个会准时还款的人对银行影响不大,接受一个不会准时还款的人,那对银行可就是实打实的损失了。
对于这类问题,我们可以使用一系列的指标来对模型进行评估,如混淆矩阵,F1,P-R曲线,ROC曲线,AUC等,听着好像很多很复杂,但其实这些指标本质都是相通的,只要理解了混淆矩阵,剩下的就水到渠成了。至于标题为什么加上了ROC曲线呢?因为这是最常用于衡量模型一种工具,我觉得值得放在标题里面。
混淆矩阵
在介绍混淆矩阵之前,我们首先需要做一点铺垫。在一个数据集被模型预测之后,其可以被分为四个集合,分别为
TP(True Positives):正样本,且被预测为正,也就是被正确预测了
FP(False Positives):负样本,但被预测为正,也就是被错误预测了
TN(True Negatives):负样本,但被预测为负,也就是被正确预测了
FN(False Negatives):正样本,但被预测为负,也就是被错误预测了
这样看着可能有点乱,我们将其总结为下图
将上述表格写成一个的矩阵就是混淆矩阵,一般在sklearn
中我们绘制出的混淆矩阵图长这样
精确率与召回率
下面用TP, FP, TN, FN分别代表其对应集合中的样本数量,我们可以计算出各种指标。
精确率:
也叫查准率,定义为
其代表被划分到正类的样本中,划分正确的样本占比,例如上述的银行贷款场景,我们就可以要求精确率尽可能的高。
召回率:
也叫查全率,定义为
其代表所有正类样本中,被划分到正类的样本占比,例如作物初筛,我们不希望浪费达到标准的作物,并且后续处理过程中还会有其他筛选工序可以继续筛选劣质的作物,那我们就可以要求召回率尽可能的高。
精确率与召回率的关系
一般来说,精确率与召回率是相互约束的。大多数模型用于分类时,其输出会是该样本被分到一个类别的概率,然后再根据我们所设定的阈值被划分到不同的类别。虽然在二分类问题中,这个阈值一般会被设置为0.5,但是在不平衡学习问题中,可以根据我们的需求调整这个阈值。
例如还是上述的银行贷款问题,记通过的为1,不通过的为0,模型输出为样本被分为1的概率,我们就可以将阈值上调,如上调至0.7。这时精确率与召回率会发生什么变化呢?首先可以确定的是,召回率一定会变小,因为其分母是一个定值,就是所有真值为1的样本嘛,其此调高阈值必然会导致,也就是被划分到正类的样本数下降,因为被划分的正类的门槛更高了。而精确率在一般情况下则会上升,因为高门槛也会过滤掉更多被错误分类至正类的样本,可以结合下图理解一下。
因此,如果同时拥有高精确率与高召回率的模型,则其性能是非常优秀的,也就是说这个模型可以把样本分的很开,正类样本都很接近1,负类样本都很接近0。我们可以用一个统一的指标来衡量模型的精确率与召回率,这就是F1值,其为精确率与召回率的调和平均,定义为
当然,当我们对精确率与召回率的重视程度不一样时,我们可以通过权重来控制,定义为
当时,召回率有更大的影响,反之,精确率有更大影响。
P-R曲线
在模型已经完成训练后,我们也可以通过精确率与召回率来选择合适的阈值,具体操作为,将所有样本的概率值从小到大排序,然后从0开始,将每两个相邻样本的概率值均值依次作为阈值,并计算一次精确率与召回率,最后以为轴,为轴,绘制散点图并连接成曲线,这也就是P-R曲线,可以结合下图理解一下
注:其实阈值的增大并不用那么严格,就算是从0开始,每次加0.1加到1为止都是可以的,画出来的学习曲线没什么区别
最终画出来的P-R曲线大概长这样
通过P-R曲线我们可以根据自己的实际需求,选择合适的阈值。除此之外,我们也常常用P-R曲线包住面积的大小来衡量模型的优劣,而在模型的P-R曲线有交叉时,除了根据我们的需求选择模型,还可以通过平衡点处的取值来衡量模型的优劣。平衡点就是指P与R取值相同时,模型的P或R的取值(反正是一样的嘛),这也被称为BEP,当然实际使用中还是F1用的多一点。
ROC曲线
TPR与FPR
在介绍ROC曲线之前,我们要先来看看TPR(True Positive Rate)与FPR(False Positive Rate),这也是由TP, FP, TN, FN计算出的指标,其具体定义为
从定义我们可以看出,TPR代表真值为正的样本被正确分类的概率,其定义与召回率是一样的。FPR代表真值为负的样本被错误分类的概率。
ROC曲线
与P-R曲线相同,我们可以通过调整阈值的方式,得到多组TPR与FPR以得到ROC曲线,示例图如下
我们当然希望TPR尽可能高,FPR尽可能低,那么自然就是ROC曲线越靠近左上角则代表模型的效果越好,因此也经常使用曲线盖住的面积来衡量模型的效果,这被称为AUC值,也就是图中图例的部分。另外,图中的对角线代表随机猜测下的结果,ROC曲线离这条线越远越好。
注:ROC曲线靠近左上角最好,那什么情况最差呢?靠近右下角?错的,其实是与虚线重合,如果ROC曲线靠近右下角其实跟靠近左上角一样,是很好的结果,这说明模型学反了,但是学的很好,把结果反过来看就可以了,当然实际不太可能出现这种情况。
sklearn代码绘制
最后我们来说明一下如何使用sklearn
库实现我们上述讲到的内容,其主要都在sklearn.metrics
中,下面导入需要的库
1 | import matplotlib.pyplot as plt |
我们使用乳腺癌数据集作为示例数据集,下面我们导入数据并完成模型的训练
1 | data = load_breast_cancer() |
首先我们来计算精准率,召回率与F1值,使用函数precision_score
,recall_score
与f1_score
,参数也很简单,填入真值与预测值即可,其余参数都不算很常用。
1 | # 计算P,R,F1 |
然后是绘制混淆矩阵,使用函数confusion_matrix
,当然这个函数只负责算出混淆矩阵,绘图还是需要用motplotlab
写,参数同样是填入真值与预测值,其返回值就是混淆矩阵。
1 | #绘制混淆矩阵 |
接着是绘制P-R曲线,使用函数precision_recall_curve
,需要注意的是,其参数填入的是真实值与每个样本的预测概率值,这可以通过模型的predict_proba
方法计算,这会获得每个样本被分到0与1的概率,我们只需要样本被分到1的概率。函数的返回值有三个,分别为P,R与每一次计算的阈值,一般我们不需要阈值,这里使用_
代替,表示不需要该返回值。
使用average_precision_score
函数可以计算AP值。这里的AP值是P-R曲线面积的一种精度更高的算法,使用的时候理解为面积即可。
1 | # 绘制P-R曲线 |
最后是绘制ROC曲线,使用函数roc_curve
,其参数同P-R曲线,填入真值与概率值,返回值为FPR,TPR与每一轮计算的阈值。
使用auc
可以计算曲线包住的面积,填入FPR与TPR即可。
1 | #绘制ROC曲线 |
补充:上述提到的绘图
sklearn
都进行了封装,这里也一并给出示例代码
1
2
3
4
5
6
7
8
9
10
11 # 混淆矩阵
from sklearn.metrics import plot_confusion_matrix
plot_confusion_matrix(clf, Xtest, Ytest)
# P-R曲线
from sklearn.metrics import plot_precision_recall_curve
plot_precision_recall_curve(clf, Xtest, Ytest)
# ROC曲线
from sklearn.metrics import plot_roc_curve
plot_roc_curve(clf, Xtest, Ytest)