机器学习实战—分类问题学习笔记(二)

四、二分类器性能考核

3. 精度/召回率权衡

书接上文,我们了解到了所谓的精确率和召回率,但是在不同的情况下我们对精确度和召回率重视程度不同,因为精确率与召回率是此消彼长的关系, 如果分类器只把可能性大的样本预测为正样本,那么会漏掉很多可能性相对不大但依旧满足的正样本,从而导致召回率降低,正所谓鱼和熊掌不可兼得,你不能同时增加精度并减少召回率,反之亦然,这就称为精度和精确率的权衡问题。我们想要了解精度/召回率的权衡过程,首先了解一下随机梯度下降分类器的分类原理,该分类器会基于决策函数计算出每个实例的一个分数,然后会将这个值跟分类阈值进行比较,如果大于该阈值该实例就会判正,否则就会判负。基于前面的判断是不是五的二分类器,这里取出一串数字,和三个阈值来对精度和召回率的权衡做一个分析,首先看中间的阈值2,可以发现阈值右侧有4个真正类(TP)(4个5)和一个假正类(FP)(一个4),此时精度为80%,但对于所有的5只有4个判断出来了(4个真正类TP,两个假负类FP),此时召回率为67%,如果现在提高阈值为阈值3,此时精度变为100%召回率变为50%,再看阈值1,此时精度为75%,召回率为100%,这也更加证实了精度和召回率是一个此消彼长的概念。
在这里插入图片描述

在Scikit-Learn中是不允许直接设置阈值的,但是可以通过访问这个阈值来进行预测每个实例对应的决策分数,使用decision_ function方法就可以返回每个实例的分数,这样就可以根据这些分数来预测任意阈值了。SGDClassifier分类器使用的阈值默认为0,下面使用36000号图像,查看其预测分数

y_scores=sgd_clf.decision_function([X_train[36000]])
y_scores

运行结果:
在这里插入图片描述
结果分析:可以看出36000号图像的阈值为负数,即小于阈值0,分类器会判负,所以36000最后的预测结果为不是5

阈值的变化会影响到我们的召回率和精确度,那么在实际问题中该如何选择一个合适的阈值来达到我们的需求,这里我们可以了利用一些有用的API来计算出精确度和召回率与阈值的变化关系,最后来选择合适的阈值,Python代码实现如下:

from sklearn.metrics import precision_recall_curve
y_scores=cross_val_predict(sgd_clf,X_train,y_train_5,cv=3,method="decision_function")#与前面获得预测结果不同,这里使用该函数获得预测分数
precisions,recalls,thresholds=precision_recall_curve(y_train_5,y_scores)#根据上面计算出所有可能阈值对应的精度和召回率
def plot_precisoin_recall_vs_threshold(precisions,recalls,thresholds):#图像观察变化更加清楚
    plt.plot(thresholds,precisions[:-1],'b--',label="Precision")
    plt.plot(thresholds,recalls[:-1],'g-',label="Recall")
    plt.xlabel("Threshold")
    plt.legend(loc="upper left")  #会显示前面定义的label信息,在左上角
    plt.ylim([0,1]) #设置y轴的底和高
plot_precisoin_recall_vs_threshold(precisions,recalls,thresholds)
plt.show()

运行结果:
在这里插入图片描述
结果分析:从上图可以看出精确度和召回率与阈值变化的一个关系当然我们也可以更佳的方法就是直接绘制精度和召回率的函数图,这样就更好权衡精度和召回率的一个变化关系了:

plt.plot(recalls[:-1],precisions[:-1],'b-')
plt.xlabel("召回率")
plt.ylabel("精度")
plt.show()

在这里插入图片描述

4. ROC曲线

ROC曲线是一种和二元分类器一起使用的工具,它与精度/召回率曲线非常相似,但绘制的不是精度和召回率,而是真正类率TPR(召回率的另一种名称)和假正类率FPR。TPR是所有真实类别为1的样本中,预测类别为1的比例。FPR则为所有真实类别为0的样本中,预测类别为1的比例,它等于1减去TNR(真负类率),TNR为被正确分类为负类的负类实例比率,也称为特异度,ROC曲线横轴是FPR,纵轴为TPR,ROC曲线本质上绘制的是灵敏度和(1-特异度)的关系
在这里插入图片描述
在这里插入图片描述
下面对ROC曲线进行绘制

#绘制ROC曲线
from sklearn.metrics import roc_curve
fpr,tpr,thresholds=roc_curve(y_train_5,y_scores) #计算TPR和FPR
plt.plot(fpr,tpr,linewidth=2,label=None)
plt.plot([0,1],[0,1],'k--')#这是一条过原点斜率为1的直线,在ROC曲线中表示的意义是对于真实类别无论是1还是0的样本,分类器预测的概率都是相等的
plt.axis([0,1,0,1])
plt.xlabel("FPR")
plt.ylabel("TPR")
plt.show()

运行结果:
在这里插入图片描述
结果分析:可以发现TPR(真正类)越高,分类器产生的FPR(假正类)就越多,评断一个分类器否够优秀的的原则就是看其ROC曲线偏离虚线越远越好。

AUC介绍
AUC和ROC曲线是息息相关的,其表示的意义是随机取一对正负样本(真实情况下而不是预测情况下取)正样本得分大于负样本的概率,AUC本质上就是ROC曲线的积分(也就是面积),AUC的最小值为0.5(这是随机分类器的ROC),最大值为1(这是完美分类器的ROC),当AUC大于0.5小于1时,表示这个预测模型要好于随机预测,如果我们妥善的去设置阈值的话,该模型有其一定的预测价值。下面计算AUC:

#AUC
from sklearn.metrics import roc_auc_score
roc_auc_score(y_train_5,y_scores)

运算结果:
在这里插入图片描述

我们可以发现ROC曲线和前面的精确度/召回率曲线(PR)曲线很类似,在选择用哪一个曲线进行评估时,应该遵循的原则是,当正类很少时我们选择PR曲线,相反则选择ROC

拓展:为了进一步优化分类效果,这里再使用另一类分类器RandomForestClassifier(随机森林分类器)来进行预测并绘制ROC曲线,现在存在的问题就是,在我们绘制ROC曲线需要知道每个实例都测试分数,当随机森林分类器没有decision_function方法,它只有一个dict_proba方法,该方法返回一个二维数组,该数组每行为一个实例,每列代表一个类别,意思是某个给定实例属于某个类别的概率,于是我们直接使用属于正类的概率作为分数值,具体代码如下:

from sklearn.ensemble import RandomForestClassifier
forest_clf=RandomForestClassifier(random_state=42)
y_probas_forest=cross_val_predict(forest_clf,X_train,y_train_5,cv=3,method="predict_proba")#还是使用交叉验证
y_scores_forest=y_probas_forest[:,1]
fpr_forest,tpr_forest,thresholds_forest=roc_curve(y_train_5,y_scores_forest)
plt.plot(fpr,tpr,"b:",label="SGD")
plt.plot(fpr_forest,tpr_forest,label="RandomForest")
plt.legend()
plt.show()

在这里插入图片描述
结果分析:上面SDG和RandomForest两个分类器的ROC曲线进行了比较,可以发现随机森林分类器的效果是更优的

五、多分类分类器

1.简介

前面都是介绍的二元分类器在两个类别中区分,而多分类别分类器(也称为多项分类器)可以区分两个以上的类别。

2.OVA和OVO策略介绍

拿前面的Mnist数据集来分析,要创建一个多分类器,我们可以采取的一个策略是,给每个数字创建一个上面的那个判断是否为5的分类器,然后对每个模型进行训练,获取每个模型对需要预测图片实例的决策分数,预测分数最高的那个类即为该类的所属类。这种一实例对多模型的策略(一对多策略)成为OVA策略
在这里插入图片描述

Scikit-Learn可以检测到你尝试使用二分类算法进行多类别分类任务时,它会自动运行OvA策略,如下:

sgd_clf.fit(X_train,y_train) #直接在原数据集上训练
sgd_clf.predict([X_train[36000]])

运行结果:
在这里插入图片描述
结果分析:可以发现结果是8(我们可以查看y_train[36000]知道预测正确),按照OvA策略,SGD应该是选择了判8分类器,下面查看预测分数:

some_digit_scores=sgd_clf.decision_function([X_train[36000]])
some_digit_scores

运行结果:
在这里插入图片描述
结果分析:可以看出8分类器的分数982最高,所以预测结果为8

OVO这是不同于OVA的另一种方法,它对每两对数字训练一个二元分类器,也就是类别之间两两一对一,对于Mnist问题需要n*n-1/2个分类器(排列组合问题),这就是OVO策略,其优点在于每个分类器只需要使用到部分训练集对戏必须区分的两个类别进行训练。
在这里插入图片描述

在我们需要强制Scik-learn使用OVA或OVO策略时,可以使用OneVsOneClassifier或OneVsRestClassifier,只需要创建一个实例,然后将二元分类器作为参数就可:

from sklearn.multiclass import OneVsOneClassifier #OVO
ovo_clf=OneVsOneClassifier(SGDClassifier(random_state=42))
ovo_clf.fit(X_train,y_train)
ovo_clf.predict([X_train[36000]])

最后前面介绍OVO和OVA都是以随机梯度下降分类器作为分类器,这里我们在多分类问题时不需要让Scikit-Learn运行OVO或OVA了 ,直接将X_train和y_train传递给它即可,然后预测我们要预测的数字,即可得出预测结果,到此分类问题的模型训练和预测以及模型评估都结束了下面为了进一步改进模型,我们开始进行错误分析。

六、错误分析

1. 简介

通过前面的操作我们已经找到了一个有潜力的模型,现在我们需要对模型进行进一步改进,方法之一就是进行错误分析。

2. 实操

首先我们先看看SGD预测器的混淆矩阵,然后通过Matplotlib()函数来查看混淆矩阵(因为混淆矩阵记录了我们预测器预测的各种情况,通过对混淆矩阵的分析我们可以深入的了解如何改进分类器):

y_train_pred=cross_val_predict(sgd_clf,X_train,y_train,cv=3)
conf_mx=confusion_matrix(y_train,y_train_pred)
plt.matshow(conf_mx,cmap=plt.cm.gray)
plt.show()

运行结果:
在这里插入图片描述
结果分析:上面就是我们的混淆矩阵,颜色深浅程度代表了该种情况中数据的少多,如上图就说明大部分数据集中在对角线上(说明大部分数据预测正确),但进行错误分析我们需要看到的是错误数据的分布,所以需要对上面的混淆矩阵进行改进,方法是用矩阵中每值除相应类别图片的数量(错误率),同时将主对角设置为0(屏蔽正确数据),重新绘制结果:

row_sums=conf_mx.sum(axis=1,keepdims=True)#将矩阵每一行相加求每一类的数据总量
norm_conf_mx=conf_mx/row_sums
np.fill_diagonal(norm_conf_mx,0)#填充主对角
plt.matshow(norm_conf_mx,cmap=plt.cm.gray)
plt.show()

在这里插入图片描述
结果分析:这是我们可以清楚的看到错误数据的分布了(颜色越淡数据越多)

七、总结

到此分类问题的学习就导致结束了,通过学习掌握了如何为分类任务选择好的指标,如何选择适当的精度/召回率权衡,如何比较多个分类器,以及更为概括的说,如何为各种任务创建卓越的分类系统。另外分类问题涉及多标签分类多输出分类,这里就不讨论了,有兴趣可以查看相关资料,下次我们将讨论的是线性回归问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值