本章主要讲关于分类的一些机器学习知识点。我会按照如下关键点来总结本身的学习心得:(本文源码在文末,请自行获取)html
什么是MNIST数据集git
MNIST数据集是一组由美国高中生和人口调查局员工手写的70,000个数字图片数据集。官方连接为:http://yann.lecun.com/exdb/mnist/github
这组数据集X标签是28*28大小的像素强度数值,y标签是一个该图像对应的一个真实数字。算法
咱们经过sklearn提供的函数能够对该数据集进行下载:api
这个fetch_mldata会将名字为MNIST original的数据集经过官方库中的数据集下载下来,返回的是一个dict对象。(dict对象介绍)数组
通常童鞋应该是下不下来,文章底部的连接中有对应数据供你们直接下载。缓存
你们下载完毕后,执行下方代码:安全
from sklearn.datasets.base import get_data_home
print (get_data_home())dom
查找到sklearn对于你的机器上的数据集缓存地址,将下载的文件中DataSets中的mnist-original.mat文件直接复制到显示位置便可。机器学习
如今假定,咱们数据集已经处理完毕。
每次咱们针对数据集的观察是必不可少的操做,所以先看看返回的dict对象中都有什么对咱们是有好处的:
经过加载sklearn的数据集,一般包括:DESCR(描述数据集)、data(包含一个数组,每一个实例为一行,每一个特征为一列,即咱们的x)、target(包含一个带有标记的数组,即咱们的y)
加载其中某些内容:
看出X是一个70000*784的矩阵,也能得出咱们能够训练的实例有7万个,每一个实例均可以表示成为一个28*28的矩阵(784开根号为28),对应是一个图像。y是一个标签,相应也有7万个。
咱们将其中某一个数字画出来,能够更加直观的表示:
matplotlib上一章心得说了一些使用介绍,这里不详细讲了。这里只说matplotlib中的imshow()函数。
imshow()函数功能就是针对提供的像素点,生成一张2维图片。该函数的参数很是多,具体请看连接
从显示的状况看,这个图像看上去更像是数字5,验证一下:
猜的没错,是5。
在深刻研究该数据集以前,咱们首先应该为之后的分类算法划分测试与训练集。
这里须要说明的是,MNIST数据集已经帮助咱们分好了一个数据集划分,前60,000个数据是训练集,后10,000为测试集,因此咱们直接划分便可:
可是须要注意的是,这里的每一个集合里面的数据划分很是有规律,按照0-9的顺序排列,这对于咱们的训练是存在问题的,咱们应该随机将集合从新洗牌:numpy中的random类中的permutation函数能够达到从新洗牌的目的:
具体使用请看连接。
二分类
若是咱们只须要检测其中的某一个数字,那么咱们能够将“识别某个数字与否”这个问题当作是一个二分类问题。假设咱们这里须要识别数字5,那么最后识别出的结果就只有两个:5或非5。咱们至关于须要构建一个数字5的检测器。
首先,对该任务建立目标向量(其实就是咱们所说的y,这里所作的操做是一个方便之后的处理,不作这样的处理也是能够的),这个是用来标识识别结果是否正确,标签为5的表示为true,其余为False:
构建好目标向量以后,选择一个分类算法构建咱们的分类器,这里选择随机梯度降低分类器(SGDClassifier):
从以前全部引入的估算器,无论是决策树、随机森林、仍是线性回归、逻辑回归仍是这里的随即梯度降低,sklearn针对这些模型的初始化都很是的相似,都是首先导入,而后初始化该估算器类的构造函数,这里判断咱们是否须要针对算法的某些参数进行修改,若是采用默认则直接无参初始化,若是须要,则传入须要修改的参数值,以后采用fit()函数,传入训练集的x与y,进行训练,最后获得一个训练有素的分类器。
而后咱们经过predict()函数进行预测:
因为some_digit对应的数字以前咱们发现是5,所以预测结果为Ture。
二分类的性能评估与权衡
首先,采用交叉验证测量精度。该方法的含义是使用将训练集分红K份,每次用K-1份进行训练,剩下的1份作测试,每次算出一个精确度并输出,咱们首先本身编写:
还能够用cross_val_score()函数来实现:
咱们能够发现,每次的精确度都在90%以上,最后一次居然能到96%?个人模型这么好吗?!为了让咱们放下心来,咱们能够作以下操做,设置一个很是笨的分类器,直接预测全部数字都不是5,咱们来看看精度:
看见了吗,咱们认为的最笨的分类器,居然都能达到90%的几率!有问题,绝对有问题!
我想,你已经明白了,这是由于咱们的数据中,每一个数字大概占总数的10%左右,所以猜一张图不是5的几率均可以达到90%!所以,咱们采用精确度这个指标是存在问题的。特别是,当咱们处理偏斜数据集(某类型数据很是多,数据分布不平衡的数据集)时,精确度这个性能指标是绝对不能够的。
咱们应该采用混淆矩阵的方法!
混淆矩阵,整体思路就是构成一个矩阵,这个矩阵记录统计出A类别的实例被错误的分红B类别实例的次数。具体看下图我进行解释:
(图片源自:https://blog.csdn.net/Orange_Spotty_Cat/article/details/80520839)
咱们来看这张图,咱们想看原本是猫但被误认为狗的状况有多少次,从矩阵中,咱们就找真实值为猫,预测值为狗的对应行列便可,找到能够看出是3次,这就是混淆矩阵。
咱们再升华一下这个矩阵,从理论的高度解释一下:
(图片源自:https://blog.csdn.net/Orange_Spotty_Cat/article/details/80520839)
这里的右下角的每一个白格子,都表明一种预测状况。其实对应多分类的问题,也能够转换为二分类问题,只须要将待分类的类别归为一类,剩下归为一类便可。
好了,这里的TP、FP、FN、TN要解释一下编码的构成:预测是否错误+预测的类别:
先说这么多,咱们先把概念记住,先上一波代码,构成咱们须要的混淆矩阵吧。
要计算混淆矩阵,须要一组预测才能比较,但测试集永远记住都是放在项目启动后再进行,所以咱们仍是采用交叉验证的方式进行,此次用cross_val_predict()函数:
这里注明一下,再sklearn中生成的混淆矩阵中,行表示实际类别,列表示预测类别,与以前给出的那个矩阵行列正好相反,不过咱们只要能分出TP、TN、FP、FN就好。
从这个混淆矩阵中,咱们能够发现53517张被正确预测为“非5”的类别,4236张被正确预测为“5”的类别,1185张被错误的分为“非5”的类别,1062张被错误的分为“5”类别。
最优的混淆矩阵应该是只存在T开头的属性,其余状况的数字应该是0。
混淆矩阵能够给咱们提供大量的信息,但若是指标若是能更简介些,咱们能够更加直观的了解一些最须要的信息,接下来介绍精度、召回率的概念。
首先,给出精度的概念:
该公式计算的是正确被分为正类占预测器所有预测为正类的数量的比率。为何叫精度呢?咱们能够这么想,预测正类有这么多,其中预测的对的数量又有这么多,这不就是计算了一个精度嘛?
接下来,咱们谈谈召回率:
该公式计算的是正确被分为正类的数量占总正类数量(由于FN对应这些状况的真实值应该是正类呀)的比率。为何叫召回率呢?咱们能够举个例子来思考这个问题。好比车吧,车厂在出售车以前,须要对车进行一个检测,咱们这里定义的正类就是“存在问题的车”。固然存在有些车自己存在问题,但没检测出来就售出了,而后呢车厂发起召回问题车,这时候咱们就须要召回率来帮忙了!固然,咱们可想而知,召回率过高,估计老板得气死。。-。-言归正传,召回率也叫查全率,就是计算的是总共的正类中,我一共能正确分出多少的正类的比率。
上代码,计算吧:
发现没,这个分类器没有以前那么亮眼了,我就知道!!哼!!
咱们还有一个指标能够结合上述两个指标,那就是,,,,,F1分数!
上公式:
怎么理解F1分数呢?F1分数是精度和召回率的谐波平均值。正常的平均值平等对待全部值,而谐波平均值会给予较低的值更高的权重。所以当召回率和精度都很高时,分类器才能获得较高的F1分数,所以F1分数越高,能说明,咱们的系统更加稳健。
可是,咱们不该该把追求F1分数做为咱们的最终目标,咱们要看实际的要求权衡召回率和精度,举个例子让你们明白:
假设,须要训练一个分类器来检测儿童能够放心观看的视频,咱们应该本着宁肯错杀100不可放过一个的目的,可能会拦截好多好视频(低召回率),但确保保留下的视频都是安全的(高精度)。相反,若是须要训练一个分类器经过图像监控检测小偷,这个分类器应该本着无论这我的是不是不是小偷,当他作相似小偷的行为时,就应该发出警报。因此咱们固然但愿的是尽量抓住更多的小偷咯,所以咱们要求召回率要达到99%以上(可能会误报不少次,但几乎窃贼都在劫难逃!),但这样的话,咱们的精度是会降低的。
接下来解释一下为什么精度和召回率不能兼得:
让咱们想一个问题,在极端的状况下,假设你在查找一个问题的答案,若是要求精度很是高,那么返回的结果就会不多,但都是你要的,若是要求召回率(查全率)很高,那么返回的结果不少,但其中有不少的结果是你不须要的。所以,须要高精度就会致使低召回率,反之亦然。
返回到咱们的数字分类的问题上,咱们看一下SGDClassifier如何进行分类决策的。
这个分类器,对于每一个实例,它会基于决策函数计算一个分值,若是该值大于阈值,则断定为正类,不然为负类。放个图,解释一下:
假设,咱们阈值在中间箭头位置,在阈值的右侧能够找到4个真正类(四个5),一个假正类(一个6)。所以,在该阈值下,精度为80%(4/5),召回率为67%(4/6)。当咱们提升阈值,假正类的6就会变成负类,那么精度会提高到100%(3/3),但一个真正类变成了一个假负类,召回率变为50%(3/6)。
sklearn不容许直接设置阈值,可是能够访问它用于预测的决策分数,咱们能够基于分数,使用阈值预测,上代码:
咱们如何选择阈值呢?咱们先获取训练集中全部实例的分数:
再使用precision_recall_curve()函数计算全部可能的阈值的精度和召回率,最后绘制精度和召回率相对于阈值的函数图像:
还有一种与二元分类器一块儿使用的工具:受试者工做特征曲线(ROC),该曲线绘制的是召回率和假正类率(FPR:被错误分为正类的负类实例比率,等于1-真负类率[被正确分类为弗雷德负类实例比率,也称为特异度])。
使用roc_curve()函数计算多种阈值的TPR和FPR,而后绘制FPR对于TPR的曲线:
一样,召回率越高,分类器产生的假正类越多,虚线表示纯随机分类器的ROC曲线,一个优秀的分类器应该离这条线越远越好。有一个比较分类器的方法是测量曲线下面积(AUC):
那么,问题来了,如何选择指标呢?这里直接引用书上的原话:当正类很是少见或者你更关注假正类而不是假负类时,你应该选择PR曲线,反之ROC。
训练一个随机森林的分类器,并比较SGD分类器:
计算它的AUC得分:
它的精度和召回率以下:
从二元分类到多分类
咱们的数字分类问题,能够分为10个二分类问题,在检测图片分类时,能够获取每一个分类器的决策分数,哪一个分高就决定时哪一个数字。这是OvA策略,一对多。还有一种状况能够为每一对数字训练分类器,这称为OvO,一对一策略。
有些算法在数据规模扩大时,表现糟糕,对于这类算法,一对一是优先选择,若是不是的话就一对多。
sklearn会检测到你尝试使用二元分类算法进行多类别的分类任务,它会自动进行OvA:
每一个类别得出的分数以及分类器分出的类别咱们均可以知道:
咱们也能够进行一对一的分类策略,预测器的个数也能显示出来:
至于评估分类器,提高准确率,这里再也不赘述。只放代码,本身看就好:
错误分析
这里,假设咱们已经找到了一个有潜力的模型,咱们但愿对该模型进行改进,咱们能够分析其错误类型,帮助咱们。
首先能够看看混淆矩阵:
我擦,数字有点多,看的不清楚,怎么才能更形象的表示呢?咱们能够将该矩阵可视化:
越白是表示数字越多,越黑表示数字越少。因为大多数白色都在对角线上,因此咱们能够认为大部分的数字与图片能够正确分类。从局部上,咱们能够发现,白色的部分也存在差别,数字2的白色就很好,而数字五、数字8看起来比其余的要差一些,可能的缘由有:数据集中图片较少,或者数字5在执行效果上不如其余数字。
咱们把问题集中在错误上,将混淆矩阵中的每一个值除以相应类别中的图片数,得出错误率:
而后用0填充对角线,只保留错误率,从新绘制:
目前,就能够看出分类器产生的错误种类了。记住行为实际类别,列为预测类别。咱们能够发现,第6列第4行和第4列第5行两个格子很亮,说明分类器针对数字三、数字5容易混淆,其余的白色格子,咱们能够进行一样的分析。
下面,咱们来具体看一下数字3和5分错的图片混淆矩阵。首先定义一个数字图像显示的函数:
上述定义的函数你们直接拷贝便可,若是想深刻研究其中的运行原理,请参考具体的文档进行查看,不过也不会难,只是须要必定的逻辑就好。
而后对图片进行一个显示:
上图中,左侧两个5*5的矩阵显示的是被分类为数字3的图,右侧两个5*5的矩阵显示了被分类为5的图。分类器弄错的数字就是左下方和右上方的图片。经过对比,咱们能够发现有些数字用人脑来分辨也真的很容易分错,所以知道分类器在具体的分类问题上的差别后,咱们就应该根据具体的问题,经过具体的手段进行修正。好比多采集数字3和数字5的数据,或者针对数字3和5的形状结构,开发新的特征来改进分类器,对图像预处理,或者采用更高级的算法等等来解决问题。
多标签分类、多输出分类
咱们以前所做的分类器都会将一个实例分在一个类别中,而在某些状况下,须要分类器为每个实例产出多个类别。好比分类照片中的人像,一张照片可能存在不少我的,分类器就能够输出照片中的人对应的姓名。这种输出多个二元标签的分类系统成为多标签分类系统。
接下来,咱们针对这个问题,建立一个多标签数组,这个数组包含数字图片的目标标签:第一个数字表示是否大数(7,8,9),另外一个表示该数是不是奇数。咱们这里须要注意的是,不是全部算法都能支持多标签的分类,咱们这里选择KNeighborsClassifier分类器进行分类:
咱们会发现,最后输出的结果就是一个多标签的结果。
最后,咱们讨论一下多输出分类。
这种类型的任务全称应该叫多输出—多类别分类,简单来讲是多标签分类的泛化,其标签也能够是多种类别的。用一个例子来解释:咱们如今须要针对含有噪声的图片进行去噪处理,就用咱们的手写图像为例。咱们构造的这个系统输出就是多个标签(一个像素点一个标签),每一个标签能够存在多个值(0-255)。这个任务比起分类任务来讲,更像回归任务,可是咱们须要注意的是分类和回归的界限有时很模糊,咱们其实没必要要必定要分的很细,适合咱们的目的就好,灵活掌握。
来,最后上一波代码,说明上述的这个问题。固然,咱们首先要添加噪声,而后编写图像显示的函数,最后对比一下输出就好:
第四章的心得总结就到这里,我经过第四章的学习,将以前对召回率、精度、ROC曲线、F1分数等一系列概念有了更深的了解,但愿经过本身的心得总结,可以帮助更多的人,谢谢。
源码获取:
一、个人Github:https://github.com/niufuquan1/MyStudy_For_sklearn_tensorflow/tree/master/ML_MNIST
二、百度云:https://pan.baidu.com/s/1sX2ulOE7xgjJTzfVmA0N0Q (rxfv)