当前位置:   article > 正文

Scikit-Learn&TensorFlow机器学习实用指南(四):分类【上】

Scikit-Learn&TensorFlow机器学习实用指南(四):分类【上】

机器学习实用指南(四):分类【上】

作者:LeonG
本文参考自:《Hands-On Machine Learning with Scikit-Learn & TensorFlow 机器学习实用指南》,感谢中文AI社区ApacheCN提供翻译。

本文全部代码和数据集保存在我的github-----LeonG的github

机器学习的监督学习任务中最常见的任务是回归(用于预测某个值)和分类(预测某个类别)。

分类任务

回归任务

在这一章,我们重点来学习分类任务

Scikit-Learn包是一个集成了大部分机器学习经典算法的python库,它可以帮助我们快速上手机器学习的众多应用。

注意:本项目主要使用Jupyter Notebook进行开发,Jupyter Notebook是一个简便易上手的python工作环境,源代码请使用Jupyter Notebook打开。

1.MINIST数据集

1.1下载数据集

首先给大家介绍一下机器学习的经典数据集–MNIST,它是拥有70000张手写数字图片的数据集合。这个数据集经典程度相当于机器学习领域的“Hello World”。

from sklearn.datasets import fetch_mldata
#先将mnist数据集下载到项目目录(./mldata/mnist-original.mat)
#下载地址:https://github.com/amplab/datascience-sp14/raw/master/lab7/mldata/mnist-original.mat
mnist = fetch_mldata('MNIST Original',data_home='./')
mnist
  • 1
  • 2
  • 3
  • 4
  • 5

介绍一下这三个标签的意义:

  • DESCR键描述数据集

  • target键存放一个标签数组

  • data键存放一个图片数组,数组的一行表示一个样例,也就是一张图片

然后看看这个数据集的结构,主要是查看维度

x,y = mnist["data"],mnist["target"]
x.shape
y.shape
  • 1
  • 2
  • 3

现在我们总结一下MNIST数据集的特点:

MNIST有70000张图片,众所周知,图片是由像素点构成的。

784意味着每张图片拥有784个像素点,这是因为每张图片都是28*28像素的,且每个像素点都介于0~255之间。

target标签表示对应位置的图片是什么数字。

我相信每个接触到MNIST数据集的人都迫不及待地想看一下图片是什么样子了,说实话我也是(搓手手),让我们随便展示一张图片。

import matplotlib
from matplotlib import pyplot as plt
some_digit = x[36000] #第36001张图片
img = some_digit.reshape(28,28)  #还原成28*28的结构
plt.imshow(img,cmap = matplotlib.cm.binary, interpolation="nearest")
plt.show()
y[36000] #顺便看一下标签
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

哟,不错,整挺好,可以看到图片上的数字和标签正好对应起来了,有了这样一个利器,我们就能慢慢揭开机器学习分类任务的神秘面纱了。

部分mnist图片

1.1划分训练集

少侠稍安勿躁,在进行下一步之前,我们总是要先将数据集分为训练集和测试集两个部分,最好还能打乱一下顺序,因为有的算法对顺序的敏感度很高。

  1. 把前60000条化为训练集,后10000条归为测试集
  2. 打乱训练集的顺序,测试集的顺序mnist已经帮我们打乱好了
#分割数据集
x_train,x_test,y_train,y_test = x[:60000],x[60000:],y[:60000],y[60000:]
#打乱训练集
import numpy as np
shuffie_index = np.random.permutation(60000)
x_train,y_train = x_train[shuffie_index],y_train[shuffie_index]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

接下来正式开始学习分类任务。

2.训练一个二分类器

鲁迅曾经说过:学走先学爬(鲁迅:我没说过),多分类属于比较高级的分类任务,我们先做个简单的,比如鉴定一张图片是否是数字5

这个“数字 5 检测器”就是一个二分类器,能够识别两个类,“是5”和“非5”。让我们为这个分类任务创建新的标签,也就是将所有数字标签转为是和否两种标签(bool类型)

y_train_5 = (y_train == 5) #训练集的标签
y_test_5 = (y_test == 5) #测试集的标签
  • 1
  • 2

接下来就是选择一个分类器了,给大家介绍一下本次的主角SGD(随机梯度下降分类器)。其实随机梯度下降分类器并不是一个独立的算法,而是一系列利用随机梯度下降求解参数的算法集合。

这个分类器默认用的算法是SVM(线性支持向量机),既然是线性的,自然就适合二分类方法,毕竟非黑即白嘛。而且该分类器的好处是处理大量数据时非常高效,让我们先创建一个SGDClassifier分类器然后训练一遍。

from sklearn.linear_model import SGDClassifier
sgd_clf = SGDClassifier(random_state=42)
sgd_clf.fit(x_train,y_train_5) #训练分类器
  • 1
  • 2
  • 3

这里的代码很常用所以解释一下,首先调用SGDClassifier函数新建了一个分类器,随机种子设为42,算法中需要的参数都是按照某种方式随机生成的,然后调用fit训练函数,输入训练数据,通过梯度下降法训练参数,最后得到的sgd_clf是训练好的分类器

现在随便测试一张图片:

sgd_clf.predict(X[36000])
  • 1
array([ True], dtype=bool)
  • 1

分类器猜测这个数字代表 5( True )。看起来在这个例子当中,它猜对了。现在让我们评估 这个模型的性能。

3.评估性能

首先我们应该使用交叉验证法,具体原理参考上一章中提到的K这交叉验证法。在这里我们只管调用函数 cross_val_score就好了。

K = 3意味着将把训练集分成3折,使用其他折进行训练,剩下的折用于测试精确度。

from sklearn.model_selection import cross_val_score
#cv代表折数,scoring为计算方式,这里计算精准度
cross_val_score(sgd_clf,x_train,y_train_5,cv = 3,scoring="accuracy")
  • 1
  • 2
  • 3
array([ 0.9502 , 0.96565, 0.96495]
  • 1

看起来准确率非常高,但是并不是这样的,想象一下,假如你全猜“非5”,准确率依然有90%!这是因为图片5的数量太少了,只占总数据的十分之一。所以准确率并不能很好的表达模型的精度。

那怎么样才能判断模型的精准度呢,现在我们打开新世界的大门。

3.1混淆矩阵

对于分类器来说,混淆矩阵是个不错的判断精度工具,什么是混淆矩阵呢?

大致的意思就是类别A被判断为B的次数,我们做一个简单的表格就能看懂了,其中加粗的对角线就是正确分类的数量。

首先,我们使用K折交叉验证得出一系列的预测,也就是模型得出的预测值。使用函数cross_val_predict,注意,有别于上面提到的 cross_val_score,那个是分数,这个是预测值,然后使用函数confusion_matrix得到混淆矩阵,是不是很简单?

from sklearn.model_selection import cross_val_predict
#计算预测值
y_train_pred = cross_val_predict(sgd_clf,x_train,y_train_5,cv = 3)

from sklearn.metrics import confusion_matrix
#计算混淆矩阵
confusion_matrix(y_train_5,y_train_pred)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
array([[53887,   692],
       [ 1279,  4142]], dtype=int64)
  • 1
  • 2

来,总结一下这个矩阵中四个值代表的意义:(正例:是5,反例:非5)

53887:代号TN,全名true negative,真反例,就是反例分对了的意思。

1279:代号FN,全名false negative,假反例,就是错分为反例的意思。

692:代号FP,全名fasle positive,假正例,就是错分为正例的意思。

4142:代号TP,全名true positive,真正例,就是正例分对了的意思。

好了,我不是有意要绕晕你的,如果你没看懂,直接看图啦

形象生动(并没有)

基于以上的划分方式,我们要引出准确率、召回率这对欢喜冤家。

3.2准确率与召回率

准确率: p r e c i s i o n = T P T P + F P precision = {TP\over TP+FP} precision=TP+FPTP

召回率:$recall = {TP\over TP+FN} $

准确率的意义很简单,当模型给出一个预测时,该预测的可靠程度。

召回率是指所有正例中,被正确预测的个数。

我们测试一下刚才建立的分类模型,准确率的计算函数是precision_score,召回率是recall_score

from  sklearn.metrics import precision_score,recall_score
precision_score(y_train_5,y_train_pred)
recall_score(y_train_5,y_train_pred)
  • 1
  • 2
  • 3
0.8568473314025652
0.7640656705404907
  • 1
  • 2

也就是说,该模型有85.6%的几率预测正确,但是所有的图片5,只有76%被正确识别了。

而准确率和召回率是一对难以调和的冤家,因为当你提高准确率,也就是更加严格的判断是否为5,可能很多的图片5被误杀,导致召回率直线下降。

通俗点说:

准确率高:宁缺毋滥(判断正例的数据少,但是准度高)
召回率高:宁可错杀一千,不可放过一个(判断正例的数据多,但是准度低)

其中意味,需要你自己细细体会,这里将准确率和召回率呈现的趋势展示给大家看:

提高阈值,准确率上升,召回率下降,反之准确率下降,召回率提升,那么最好的位置就是两者都在0.8左右。

两者无法兼得,所以提出新的判断标准,F1值,近似为两者的平均值。但是计算方式考虑到了较小的值有更大的权重。

F 1 = 2 1 p r e c c s i o n + 1 r e c a l l F1 = {2\over {1\over preccsion}+{1\over recall}} F1=preccsion1+recall12

看不懂公式不重要,只要知道F1代表的是两者的平均值就好,咱们直接调函数f1_score

from sklearn.metrics import f1_score
 f1_score(y_train_5, y_train_pred)
  • 1
  • 2
0.78468208092485547
  • 1

有时候你需要很高的准确率,比如判断水果是否变质,我们只需要输出的水果都是好水果就行了。

有时候你需要很高的召回率,比如判断背包内是否携带易燃易爆物品,即使是错误识别了某些背包,也不能让危险的背包通过。

有时候你需要兼顾二者,就着力于提高F1值。

那么如何调整准确率和召回率呢?最直接的办法就是调整阈值了,简单地说就是调整判断图片是否为5的标准。

一般来说,分类器会得出一张图片是正例(是5)的得分值,我们只要调整得分值的判断标准,就相当于调整了了阈值。

调用decision_function方法,这个方法返回了每个样例的得分,然后基于这个得分,你可以任意的调整阈值。

计算所有的样例得分值方法很简单,把交叉验证函数中的method改为decision_function就可以了:

y_scores = cross_val_predict(sgd_clf, x_train, y_train_5, cv=3,method="decision_function")
  • 1

下面我们单独对第36001张图片进行判断,阈值设为0,这张图我们在前面已经看到了,是图片5

y_score = sgd_clf.decision_function([x[36000]]) #第36001张图片的得分
y_score
threshold = 0 #阈值设为0
y_some_digit_pred = (y_score > threshold) #分类
y_some_digit_pred
  • 1
  • 2
  • 3
  • 4
  • 5
array([1066.83525987])
array([ True])
  • 1
  • 2

当阈值等于0的时候,这张图片被判断为正例(是5)

阈值对准确率和召回率的影响在前面那张曲线图已经体现出来了, 你可以翻上去看看。

3.3ROC曲线

全称受试者工作特征曲线(ROC)是二分类器中常用的工具,这个曲线能反应预测为正例的数据中正确数据的比例,计算公式也很简单: R O C = P ( T P ) P ( F P ) ROC = {P(TP) \over P(FP)} ROC=P(FP)P(TP)

TP是真正例,也就是把图片5预测成5的数量

FP是假正例,也就是把不是图片5预测成5的数量

函数P就是对应的数量除以样本总数,也就是占比的意思。

再让大家复习一下这张图:

从下图的ROC曲线来看,在曲线最左上角的位置,大概是坐标(0.05,0.9)的位置。在左上角位置的时候,被错分为正例的数量最少,效果也是最好的。

调用函数roc_auc_score可以很快的算出roc值。

from sklearn.metrics import roc_auc_score
roc_auc_score(y_train_5, y_scores)
  • 1
  • 2
0.9659714668088117
  • 1

3.4小结

最后为性能评估做个总结,分类的任务远不止二分类,还有多分类方法,但是分类器的性能评估基本上都是用这些工具。

检验自己的分类器性能一般可以使用交叉验证来评估你的分类器,然后选择满足你需要的准确率/召回率位置或者是最佳ROC位置,找到合适的阈值点。至于选择哪种性能评估工具,取决于你的分类器更注重哪方面的性能。

4.本章总结

关于机器学习的分类任务上半部分就讲完了,这一章我们主要学习了如何训练一个二分类器,如何评估一个分类器的性能,下一章我们继续学习分类任务,不过主要是侧重于多分类任务~


欢迎来我的博客留言讨论,我的博客主页:LeonG的博客

我的知乎机器学习专栏:LeonG与机器学习

本文参考自:《Hands-On Machine Learning with Scikit-Learn & TensorFlow机器学习实用指南》,感谢中文AI社区ApacheCN提供翻译。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/775042
推荐阅读
相关标签
  

闽ICP备14008679号