机器学习入门 10-5 精确率和召回率的平衡

2020-04-26 15:10:00 浏览数 (1)

前言

本系列是《玩转机器学习教程》一个整理的视频笔记。本小节主要说明精准率和召回率是相互制约、相互矛盾的两个指标,通过选取不同的threshold阈值来观察精准率和召回率的变化。在具体编程中,sklearn没有直接能够传入threshold阈值的函数,但是可以使用算法的decision_function函数计算出样本的score值,然后转换为布尔向量,进而转换为元素为0,1的整型向量,整型向量即为算法在当前阈值下预测的样本类别。

a 精准率和召回率的平衡

通过上一小节的介绍,我们了解到:

  1. 对于股票预测这类场景的分类问题,我们可能会更加重视精准率precision;
  2. 对于癌症预测这类场景的分类问题,我们可能会更加重视召回率recall;
  3. 还有一些情况,比如之前介绍的鸢尾花识别和手写数字识别的分类问题,我们并没有刻意的偏向精准率或者召回率。在这类分类问题中,我们希望精准率和召回率这两个指标都越大越好,因此才会有上一小节介绍的F1 Score指标,F1 Score通过调和平均值的方式来综合精准率和召回率两个指标;

我们肯定希望精准率和召回率两个指标越大越好,我们要怎么做才能够同时让精准率和召回率这两个指标更加的大呢?对于这样的目标是实现不了的,因为精准率和召回率两个指标之间是互相矛盾的。

  • 如果让精准率提高,相对应的召回率就会不可避免的降低;
  • 如果让召回率提高,相对应的精准率也会不可避免的降低;

我们要做的是找到精准率和召回率这两个指标之间的平衡。

为了能够更好的理解精准率和召回率这两个指标是互相矛盾的关系,我们来看一下之前所介绍的逻辑回归算法。

▲逻辑回归算法

逻辑回归算法的原理:通过训练模型找到一组参数θ,θ的转置与某个样本特征Xb进行点乘运算,最终的运算结果和0进行比较:

  • 如果θT点乘Xb的值大于等于0的话,经过Sigmoid函数计算的结果p_hat就大于等于0.5,样本分类为1的概率值大于等于0.5,因此算法将这个样本分类为1;
  • 如果θT点乘Xb的值小于0的话,经过Sigmoid函数计算的结果p_hat就小于0.5,样本分类为1的概率值小于0.5,因此算法将这个样本分类为0;

基于逻辑回归算法的基本原理,引申出了决策边界的概念。

▲逻辑回归算法的决策边界

θ的转置点乘xb=0在解析几何中表示一条直线,这条直线就是使用逻辑回归算法进行分类的决策边界。

  • 如果样本点在这根决策边界直线的一侧则将这个样本点分类为1;
  • 如果样本点在这根决策边界直线的另外一侧则将这个样本点分类为0;

所以这根决策边界直线对逻辑回归算法至关重要。可能会有疑问?为什么使用θT · xb = 0这根直线来作为逻辑回归算法的决策边界呢?如果不设置为0,而是设置任意一个常量threshold(阈值),可不可以让θT · xb = threshold作为决策边界呢?

▲任意阈值的决策边界

此时的决策边界的直线方程为θT · xb = threshold,类比于θT · xb = 0这根决策边界:

  • 如果θT · xb ≥ threshold的话,就将样本分类为1;
  • 如果θT · xb < threshold的话,就将样本分类为0;

θT · xb = threshold本身也形成了一个决策边界。基于这种想法,这相当于是给逻辑回归算法引入了一个新的超参数threshold,通过指定不同的threshold值,相当于可以平移决策边界对应的这根直线,从而影响我们最终的分类结果。

接下来就来具体的看一看,threshold取不同的值是如何影响分类结果的?首先绘制一个轴,这个轴上的值可以理解成在逻辑回归算法中计算出的θT · x的值。因为有很多其它的分类算法,可能并不是通过θT · x来充当预测边界,为了不失一般性,将这个轴称为score,不论是那种分类算法,首先都是计算出一个分数值,然后根据这个分数值与设定的阈值进行比较,进而得到最终的分类结果。

▲阈值为0的score轴

现在选定阈值为0(逻辑回归算法就是以0为阈值的),如果计算出来的score分数值(逻辑回归中就是计算θT · xb的值)大于等于0的话,就将这个样本分类为1,如果score分数值小于0的话,就将这个样本分类为0。

假设现在有12个样本,它们的score值都已经计算出来并且绘制在score轴上(每个样本的score值就是逻辑回归中的θT · x),具体分布如下图所示。

▲小例子~阈值为0时的精准率和召回率

上图中一共有12个样本,其中有5个样本在阈值0的右边,表示此时这5个样本的score值大于0,有7个样本在阈值0的左边,表示此时这7个样本的score值小于0。同时这些样本用两种形式来标识,其中的五角星形状就是我们关注的那个事件,换句话说就是分类为1的那些样本点,圆圈就是那些分类为0的样本点。

此时我们选择0为阈值,那么算法就会把这些score值大于0右边5个样本点分类为1,把score值小于0的左边7个样本点分类为0。在这种情况下精准率和召回率是多少呢?

  • 精准率为4 / 5 = 0.8。精准率计算的就是在算法所有判断为1的这些样本中有多少个判断正确的样本。算法判断为1的样本点就是在阈值为0的右边的5个样本点,其中5个样本点中有4个为五角星形状,只有一个圆形,因此算法判断正确的样本一共有4个;
  • 召回率为4 / 6 = 0.67。召回率计算的就是在所有真实为1的样本点中有多少样本被算法正确识别为1。其中在这12个样本中,五角星形状的样本一共有6个,被算法正确识别为1的样本只有4个(阈值为0右边的五角星形状的样本个数);

接下来挪动阈值,比如现在将这个阈值threshold变的比0大,现在算法是以0右边的这根直线代表的score值作为阈值。

  • 计算样本的score值如果比这个阈值大或等于,则将这个样本分类为1;
  • 计算样本的score值如果比这个阈值小,则将这个样本分类为0;

▲小例子~阈值大于0时的精准率和召回率

将threshold阈值设置比0高,那么在这种情况下的精准率和召回率是多少呢?

  • 精准率为2 / 2 = 1.00。精准率计算的就是在算法所有判断为1的这些样本中有多少个判断正确的样本。此时算法只判定两个样本为1,而这两个样本确实为类别1;
  • 召回率为2 / 6 = 0.33。召回率计算的就是在所有真实为1的样本点中有多少样本被算法正确识别为1。其中在这12个样本中,五角星形状的样本一共有6个,被算法正确识别为1的样本只有2个;

接下来继续挪动阈值,比如现在将这个阈值threshold变的比0小,现在算法是以0左边的这根直线代表的score值作为阈值。

  • 计算样本的score值如果比这个阈值大或等于,则将这个样本分类为1;
  • 计算样本的score值如果比这个阈值小,则将这个样本分类为0;

▲小例子~阈值小于0时的精准率和召回率

将threshold阈值设置比0小,那么在这种情况下的精准率和召回率是多少呢?

  • 精准率为6 / 8 = 0.75。精准率计算的就是在算法所有判断为1的这些样本中有多少个判断正确的样本。此时算法只判定右边8个样本为1,这其中有6个五角星,也就是6个样本确实为类别1;
  • 召回率为6 / 6 = 1.00。召回率计算的就是在所有真实为1的样本点中有多少样本被算法正确识别为1。其中在这12个样本中,五角星形状的样本一共有6个,被算法正确识别为1的五角星样本也有6个;

通过上面的小例子看到了,当阈值分别取0、大于0以及小于0时候的精准率和召回率的值。

▲小例子~阈值取不同值时候的精准率和召回率

通过上面的小例子图示,首先看精准率这一行,随着我们阈值逐渐增大精准率也在逐渐的升高,但是召回率却在逐渐的降低。通过上面的图示也可以看出,精准率和召回率是互相牵制矛盾的两个指标。精准率升高的话召回率就会降低,而召回率升高的话精准率就会降低。

出现这种相互牵制矛盾的现象其实非常好理解。如果想让精准率升高的话,我们肯定会把特别有把握的样本才分类为1,比如现在让我们的算法只有计算样本的概率值为90%以上的时候,才将样本分类为1,甚至更为极端只有计算样本的概率值达到99%的时候才将样本分类为1,这种情况很显然会有很多真实类别为1的样本被算法抛弃分类为0,相对应的召回率就会降低。现在反过来想让召回率升高的话,相应的就需要降低判断的概率值,比如在癌症预测系统中,当系统预测出患者患有癌症的概率为10%的时候,我们就会让算法判定这名患者患有癌症,在癌症预测系统的问题中我们拉低了threshold阈值,召回率得到了提升,但是不可避免的精准率就会下降,这就是精准率和召回率这两个指标之间的平衡。

b 实验精准率和召回率的平衡

接下来就可以具体的使用程序来看一下精准率和召回率之间的平衡关系。使用手写数字识别制作有偏的二分类数据集的过程和前几个小节一样,选择样本标签是否为9作为二分类是否为1的标准,接下来使用train_test_split将数据集划分为训练集和测试集,之后在训练集上训练逻辑回归算法,并在测试集上进行预测。

通过predict函数计算逻辑回归算法对X_test的预测值。前面介绍过对于非常有偏的数据集来说F1 Score指标比直接调用score函数计算准确率更能够评估分类算法,因此有了预测值就可以计算出F1 Score的值。

有了在测试集上的预测值,相对应的混淆矩阵、精准率以及召回率的计算就非常容易了。

前面对于精准率和召回率的平衡,我们是通过调整判断样本分类为1的阈值来完成的,不过在sklearn中本身是没有这样一个函数可以让我们在具体进行predict的过程中传入分类的阈值,算法自带的predict函数都是以0作为阈值的,所以如果想要调整这个分类阈值的话,需要绕一个弯子。对于LogisticRegression这样的分类算法来说通过计算score值(逻辑回归通过计算θT · xb计算score值),然后判断这个score值是大于0还是小于0进而进行具体的分类,在sklearn中算法还有一个decision_function的函数,光看函数命名就知道它是做决策的函数,直接把X_test测试集传入decision_function函数中。

结果是一个一维向量,一维向量中的元素值就是前面小例子图示中的样本score值。我们可以通过decision_function函数来得到每个样本的score值是多少。

现在通过decision_function函数查看前10个样本的score值,并且通过predict函数查看对于这10个样本逻辑回归算法的分类结果。

前10个测试样本中的score都为负值,由于此时使用的是默认阈值为0的逻辑回归算法,因此使用predict预测前10个测试样本的分类结果都为0。

如何通过decision_function函数来实现一个基于不同阈值的分类过程呢?首先将decision_function在测试样本计算的所有score值保存起来,简单的查看一下这些score值的最大值和最小值。

比如现在将threshold阈值设置为5,换句话说,当计算样本的score值大于等于5的时候,算法将这些样本分类为1,当计算样本的score值小于5的时候,算法将这些样本分类为0。

decision_scores >= 5返回的是布尔类型数组,使用np.array并显示指定dtype将布尔型数组转换为整型数组,数组中的元素值为0或1代表当阈值为5的时候算法的分类结果。接下来计算混淆矩阵、精准率以及召回率。

现在将阈值调低,比如设置threshold阈值为-5,换句话说,当计算样本的score值大于等于-5的时候,算法将这些样本分类为1,当计算样本的score值小于-5的时候,算法将这些样本分类为0。并相应的计算混淆矩阵、精准率和召回率的值。

至此我们在sklearn中通过使用decision_function函数改变threshold阈值进而改变算法分类的标注,最终通过计算算法在新的阈值上的精准率和召回率来观察精准率和召回率之间的关系。简单回顾一下,当threshold阈值为-5、0和5的时候,精准率和召回率的变化:

  • 当阈值为-5的时候精准率为0.72,召回率为0.88;
  • 当阈值为0的时候精准率为0.94,召回率为0.8;
  • 当阈值为5的时候精准率为0.96,召回率为0.53;

当阈值从-5到0再到5的过程中,精准率逐渐的提升,而召回率逐渐的下降,这里通过使用程序的方式再次展示了精准率和召回率这两组指标它们之间是相互制约、相互矛盾的。

本小节介绍了如何使用sklearn选取分类的threshold阈值,但是会出现一个显而易见的问题,当我们具体训练一个分类算法的时候,这个threshold阈值该按照什么样的标准来进行选取呢?下一小节将会介绍一个叫做precision-recall曲线的工具,简称PR曲线。

0 人点赞