手把手带你开启机器学习之路——分类问题总览

点击上方“超哥的杂货铺”,轻松关注

本篇文章中,我们深入讨论分类问题,包括混淆矩阵,精度,召回率,ROC曲线等相关重要概念以及二分类和多分类问题,并通过sklearn来实现。主要采用Mnist数据集。相关代码和思维导图可以在后台回复“分类”获取。

认识数据集

MNIST数据集是机器学习领域一个经典的数据集,包含了0-9十种类别的手写数字。在Sklearn中可以直接使用。先来认识一下数据集。

使用fetch_openml方法可以导入mnist数据集,分别调用data键和target键可以获取数据样本和标签,一共有70000个样本,每个样本有784个特征。

可以借助matplotllibimshow函数查看具体的图形,但需要将784重新reshape成28*28的向量。

我们将前6万张图片用作训练集,后1万张图片用作测试集。并对于训练集数据进行了随机洗牌,以确保各个类别的数字分布是均匀的。

训练二元分类器

原数据集中含有0-9共10个类别,直接分类则是多分类问题。我们首先研究二分类,训练模型识别一个样本是否为“9”,即有9和非9两类,并准备了相应的训练集和测试集标签。然后使用随机梯度下降分类器训练模型。参见下面的代码,分类器将我们选取的样本预测为“非9”,显然是“错误”的。

性能度量

首先我们使用交叉验证看一下“准确率”是多少,设置CV=3,即采用3折交叉验证。

上面代码显示的结果,3次验证,模型的准确率达到了90%以上。这虽然看上去是一个不错的结果,但实际并非如此。主要原因是原训练集中数字9的比例较少,只有10%左右。这种情况下,我们猜一个图片不是9,有90%的可能性能猜对。

为了验证这一点,我们定义一个什么都不做的分类器,也能取得较高的准确率(大约也在90%)。如下面的代码所示,几乎相当于“乱猜”,也得到了看上去不错的效果。

因此为了更好地判断模型的好坏,需要引入更合理的评估标准。

混淆矩阵

混淆矩阵是评价分类问题比较有效的工具。它的行表示实际类别,列表示预测类别,对于二分类问题,则有4个元素。如下图所示:

在本例中,“9”为正类,用1表示,“非9”为负类,用0表示。实际为0,预测为0,是真负类。实际为1,预测为0,是假负类。实际为0预测为1,是假正类。实际为1,预测为1,为真正类。分类理想的情况下,混淆矩阵只有真正类和真负类。求混淆矩阵的代码如下,需要准备实际的类别和预测的类别。

以混淆矩阵为基础,可以定义更为简洁的指标:精度(precision)和召回率(recall)。

通俗地理解,精度是指预测为正类的样本有多少是真正的正类,即查准率。召回率是指真正是正类的样本有多少被找出来了,即查全率。精度和召回率通常会一起使用,也可以将二者合为一个指标,称为F1-score

F1是精度和召回率的调和平均值。只有当召回率和精度都很高时,才有较高的F1分数。计算这三个指标的代码如下,同样需要准备实际的类别和预测的类别:

也就是说,判断一张图片是9的准确率是72.8%,且只有54.5%的数字9倍检测出来了。F1得分为62.4%

F1分数对具有相似精度和召回率的分类器更有利。但对于实际的问题,我们可能关心的重点不一样。某些情况下,可能更关心精度,某些其情况下可能更关心召回率。通常精度和召回率是不能同时增加的。

例如,如果要训练一个分类器用来检测儿童可以放心观看的视频,那么我们希望分类器识别到的视频都是安全的(高精度),而不是召回率虽高,但可能会出现非常糟糕的视频的分类器。如果要训练一个检测小偷的分类器,我们更希望召回多一些,可能精度稍微低点也没有关系。

精度/召回率权衡

我们首先看一下SGDClassifier进行分类决策的过程:对于每一个样本,分类器会计算出一个分值,如果样本的分值大于阈值,则判定为正类,如果小于阈值则判定为负类。

上面图中设定了三个阈值,可以看到,提高阈值,精度上升而召回率下降,降低阈值则会增加召回率而降低精度。

为了选取最合适的阈值,我们可以对每个样本都计算出它对应的分值。然后绘制出不同阈值下,精度与召回率的关系曲线图。如下面代码所示:

前面我们使用cross_val_predict直接得出了预测的类别,这里指定method参数之后,可以算出每个样本的预测分数。

从上面的图中我们可以比较方便的选择阈值实现精度和召回率的权衡。也可以直接绘制精度和召回率的函数图,寻找二者的平衡。

上面的图比较直观地看出精度和召回率不可兼得,精度低于90%左右的时候,召回率开始急剧下降。当根据实际项目确定了精度(或者召回)之后,可以根据前面的图计算出对应的阈值,再根据对应阈值进行预测。例如,我们看出,精度为95%时,阈值大约为10000(对应的召回率则比较低)。因此除了调用predict方法(默认使用的阈值是0),也可以按照下面的方式指定阈值进行分类:

ROC曲线

ROC曲线也是二元分类中比较常用的工具,它与精度/召回率曲线很相似,但绘制的是真正类率和假正类率。真正类率(tpr)是召回率的另一种说法,假正类率(fpr)是被错误分为正类的负类实例比率,绘制ROC曲线的代码如下:

可以通过测量曲线下的面积评价分类器。完美分类器的ROC AUC等于1,纯随机分类器的ROC AUC等于0.5。计算ROC AUC的代码如下:

经验法则:该选择精度/召回率曲线(PR 曲线)还是ROC曲线?当正类非常少见或者更加关注假正类而不是假负类时,应该选择PR曲线,反之则是ROC曲线。前面的例子中,ROC曲线表明模型还不错,但PR曲线说明模型还有改进空间(还可以更靠右)。主要是因为正类的数量比较少导致的。

两个分类器的比较

这里使用RandomForest训练一个分类器,与前面SGD分类器的ROC曲线进行比较。由于工作原理不同,RandomForestClassifier中没有decision_function方法,而是有dist_proba方法。该方法返回一个数组,每行表示一个样本,每列表示一个类别,表示该样本属于该类别的概率,可以用正类样本的概率值作为分类器的分数值。之后就可以绘制ROC曲线了。代码如下:

相应的ROC AUCprecisionrecall值也可以求出:

整体来看,RandomForest的效果要好很多,不仅ROC AUC的分数高出SGD,精度和召回率也达到了97%和79.4%。

多类别分类器

与二元分类器关心两个类别相比,多类别分类器是用来区分多个类别的。随机森林,朴素贝叶斯等算法可以直接处理多分类。也有多种方式,让二元分类器处理多分类问题。

  • 策略一:OvA

    将手写数字分为10个类别(0~9),可以每个数字训练 一个分类器,一共训练10个。当需要对一张图片进行检测分类时,获取每一个分类器的决策分数,取最高分数对应的类别,划分为相应的类。

  • 策略二:OvO

    为每一对数字训练一个二元分类器:区分0和1训练一个,区分0和2训练一个,区分1和2训练一个,以此类推。如果存在N个类别,一共需要训练N*(N-1)/2个分类器。MNIST问题中需要训练45个分类器,最终看哪个类别获胜最多。该策略的优点是每个分类器只需要用到部分训练集对其必须区分的两个类别进行训练。

有些算法在数据规模扩大时表现糟糕,例如支持向量机。这类算法OvO是一个优先选择,因为在较小训练集上分别训练多个分类器比在大型训练集上训练少数分类器要快得多。但对于大多数二元分类器,OvA是更合理的选择。

当我们使用sklearn中的二元分类算法进行多类别分类任务时候,它会自动检测到,并在内部运行OvA(SVM运行OvO),最终输出相应类别。例如我们使用SGDClassifier对手写数字进行分类。

上面这段代码使用原始包含0-9的训练集进行训练,并给出了其中一个样本的预测标签。在内部,实际上训练了10个二分类器,计算出对应的决策分数,选择了分数最高的类别,从代码中也可以验证这一点。

用原始数据训练sgd分类器,目标类别的列表存储在classes_属性中,索引4对应的类别正好是4。从运行结果可以看到:decision_function方法返回了每个类别相应的得分,分值最大的对应的索引是4,因此predict方法给出的预测类别是4。(虽然我们知道这不对,正确类应该是9)

sklearn中可以强制指定使用OvO或者OvR策略,使用相应的OneVsOneClassifier或者OneVsRestClassifier

前面提到过,随机森林可以直接处理多分类。它可以直接输出每个类别对应的概率,取概率最大值的对应的类别,不需要运行OvA或者OvO

可以看到分类器预测该图片是9的概率为0.6,是4的概率为0.3,最终输出图片是9。

同样可以像之前一样使用交叉验证评估多分类的分类器。

3折交叉验证的结果,每个类别的准确率都在87%以上,这比纯随机分类器的10%的准确率要好。但仍然有较大的提升空间,比如通过特征缩放,准确率提高到了89%以上。

多分类的混淆矩阵

和之前一样,绘制混淆矩阵需要给出每个类别的预测值和实际值,最终得到10*10的矩阵,由于数字太多,可以用图形的方式查看。

对角线上是最亮的,说明大多数的图片都被分类正确了。

分析一下每个类别的错误率:

行表示实际类别,因此错误率=混淆矩阵的每一个元素除以每一行的和。计算错误率排除了每个类别绝对数量的影响,能更好地比较不同类别效果的差异。

从错误率的图形来分析。第8列和第9列很亮,说明很多图片被错误地分类为8和9。而第8行和第9行则表示8和9被错分为其他类别。这个表示错误的图形不是完全对称的。例如5被错分为8的数量比8被错分为5的数量要多。

分析单个错误

我们单独分析一下数字3和数字5。

上图中,左侧的两个矩阵表示被分类为3的样本,右侧的两个矩阵表示被分类为5的样本。左下角和右上角是分错的。确实有一些样本即使是人眼也很难做出区分。大多数分类器分错的图片还是比较直观能看出确实不正确。原因在于,SGD分类器构建的是一个线性模型,它给每一个像素分配一个类别权重,当它看到新的图像时,将加权后的像素强度汇总,从而得到一个分数进行分类。而数字3和5只在一部分像素位上有区别,因此很容易弄混。数字3和数字5的差别主要是在连接顶线与下方弧线的中间小段线条的位置:偏左时是5,偏右时是3。因此图片轻微的旋转和移位可能会对结果有影响。可以对图片进行预处理以确保图片的中心位置没有旋转,从而提高对3和5分类的准确性。

多标签分类和多输出分类

前面我们讨论的情况,每一个实例都只会被分在一个类别里,某些情况下,我们希望分类器输出多个类别。例如我们希望同时判断对于一个给定的样本是否是大数(大于等于7)和是否是奇数。训练过程如下:

首先构造一个含有多标签的数组y_multilabel,第一个标签表示是否是大数,第二个标签表示是否为奇数。使用K近邻分类训练模型,K近邻支持多标签分类。预测的结果同样也输出了两个标签,第一个表示是大数,第二个表示是奇数。

多标签分类器的评估方法很多,比如可以测量每个标签的F1分数(或者其他指标),然后进行平均。average="macro"表示所有标签同等重要,average="weighted"则给标签设置了权重,权重值为具有改标签的实例数量。

还有一种分类问题是:多输出分类,全称是多输出-多类别分类,其标签也可以是多种类别的。可以参考下面的介绍。

http://www.jeepxie.net/article/247735.html

看一下对于一张照片去除噪声的例子。它输入一张有噪声的图片,输出一个像素强度的数组表示去噪声的图片。输出的数组,其中一个像素点是一个标签,每个标签可以同时具有多个值,范围在0-255之间。

上图中左侧是我们添加了噪声的训练集,右侧是没添加噪声的原始数据作为测试集。下面是模型输出的预测结果,可以看到是接近于目标的。

小结

本文主要以MNIST数据集为例,讨论了分类问题及其评价标准。重点学习了二分类问题中的混淆矩阵,精度,召回率。ROC曲线等概念。也对多分类问题有了一定的了解。

本文小结如下面脑图所示,后台回复“分类”可以获取本文的代码、PDF文件和思维导图。

reference:

《机器学习实战:基于Scikit-Learn和Tensorflow》第三章

以清净心看世界;

用欢喜心过生活。

超哥的杂货铺,你值得拥有~

长按二维码关注我们

推荐阅读:

1.手把手带你开启机器学习之路——房价预测(一)

2.手把手带你开启机器学习之路——房价预测(二)

3.700页的机器学习笔记火了!完整版开放下载

4.在一个机器学习项目中,你需要做哪些工作?

5.简单几步,教你使用scikit-learn做分类和回归预测

6.RFM模型是什么,我用python带你实战!

7.一场pandas与SQL的巅峰大战

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值