机器学习算法模型评价方法

本文由 简悦 SimpRead 转码, 原文地址 https://www.jianshu.com/p/b4d40760156c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

第五章 模型评价方法

5.1 模型的评价方法介绍

5.1.1~5 accuracy,precision,recall,F1-score,ROC 曲线

分别画图举例,要说出应用场景,例如什么情况用什么评价标准。

  • 混淆矩阵
  • accuracy(准确率)
  • precision(精准度),recall(召回率),F1-score(宏观,微观)
  • ROC 曲线图

5.2 项目实例运用


为了对模型的效果进行评估,需要好的评估方法,还需要衡量模型泛化能力的评价标准。评价指标是机器学习任务中非常重要的一环。不同的机器学习任务有着不同的评价指标,同时同一种机器学习任务也有着不同的评价指标,每个指标的着重点不一样。如分类(classification)、回归(regression)、排序(ranking)、聚类(clustering)、热门主题模型(topic modeling)、推荐(recommendation)等。并且很多指标可以对多种不同的机器学习模型进行评价,如精确率-召回率(precision-recall),可以用在分类、推荐、排序等中。像分类、回归、排序都是监督式机器学习。

不同的机器学习任务有着不同的性能评价指标。例如,在垃圾邮件检测系统中,这个系统本质上是一个二分类问题(区分垃圾邮件 vs 正常邮件),可以使用准确率(Accuracy)、对数损失函数(log-loss)、AUC 等评价方法。在股票预测中,这其实是一个实数序列数据预测问题,可以使用平方根误差(root mean square error, RMSE)等指标;又如在搜索引擎中进行与查询相关的项目排序中,可以使用精确率-召回率(precision-recall)等等。

在对比不同模型的能力时,使用不同的评价指标可能会导致不同的结果,这就说明:模型的好坏是相对的,好的模型不仅仅取决于数据和算法,还取决于场景需求。

本章主要介绍分类学习中的常用的评价指标。

5.1.1 准确率

这是分类任务常见的评价标准,定义如下:准确率又称查准率(Precision),为分类任务中分类正确的样本数在总样本数中所占比例,错误率为分类错误的样本数在总样本中所占比例。准确率的计算方法为:

简单来说,在这样的一个应用场景中,某个社团有男的和女的两类,分类器根据自己的判断,将社团中的人分为男女两类。准确率需要得到的是该分类器判断正确的人占总人数的比例。显然,我们可以得到:假设分类器对 100 人的性别进行判断,而其中 60 人的性别判定正确,则该分类器的准确率就是 60 %(60 / 100)。

其计算代码为:

1
2
3
4
5
import numpy as np
from sklearn.metrics import accuracy_score
y_pred = [0, 2, 1, 3]
y_true = [0, 1, 2, 3]
accuracy_score(y_true, y_pred)

输出为:

根据准确率这一评价方法,我们可以在一些场景中得到一个分类器是否有效,但它并不总是能有效的评价一个分类器的工作。这样的度量错误掩盖了样例如何被分错的事实。例如,在正负样本不平衡的情况下,准确率这个评价指标有很大的缺陷。比如在互联网广告里面,点击的数量是很少的,一般只有千分之几,如果用 Accuracy,即使全部预测成负类(不点击)Accuracy 可以达到 99% 以上,这样可以完爆其它很多分类器辛辛苦苦算的值,但是这个算法显然不是被需求所期待的,那怎么解决呢?这就是 precision、recall 和 f1-score 的出现的原因了。

5.1.2 精度

准确率和错误率虽然常见,但是不一定能很好的满足需求。精度(presicion)又可以称为查准率。其中精度是检索出相关文档数与检索出的文档总数的比率,衡量的是检索系统的查准率。直观地来理解,精度是分类器的标签不能被标记为正的样本为负的能力。

对于一个二分类问题,可以将训练集的真实类别与模型预测得到的类别组合,得到以下四种类型:TP(True Positive),TN(True Nagetive),FP(False Positive),FN(False Nagetive)。所有的训练集中的样例都可以被分为这四种类型,组成一个混淆矩阵。

混淆矩阵(Confusion Matrix)是一个普遍适用的工具,它可以帮助我们更好地了解分类中的错误。混淆矩阵也称误差矩阵,是表示精度评价的一种标准格式,用 n 行 n 列的矩阵形式来表示,是对有监督学习分类算法准确率进行评估的工具。通过将模型预测的数据与测试数据进行对比,使用准确率,覆盖率和命中率等指标对模型的分类效果进行度量。 混淆矩阵是一个 N X N 矩阵,N 为分类的个数。假如我们面对的是一个二分类问题,也就是 N=2,我们就得到一个 2 X 2 矩阵,如下表所示。

真实类别 / 预测类别 正例 负例
正例 TP FP
负例 FN FN

混淆矩阵中,各个内容的含义如下:

  • True Positive 简称 TP,表示测试集中是 Positive,模型预测结果是 Positive 的数据条目,即将正例判断为正例。
  • False Positive 简称 FP,表示测试集中是 Negative,模型预测结果是 Positive 的数据条目。
  • False Negative 简称 FN,表示测试集中是 Positive,模型预测结果是 Negative 的数据条目。
  • True Negative 简称 TN,表示测试集中是 Negative,模型预测结果是 Negative 的数据条目。

对于一个 m 分的标准分类问题来说,也可以定义如上表所示 m×m 的 m 分混淆矩阵和每一个类属的 Recall、Precision、F-measure 和 Accuracy 值。

从混淆矩阵中,可以衍生出各种评价的指标。(图片 from 维基百科)

混淆矩阵的代码实现如下:

1
0.5

对于二分类问题( binary problems ),我们可以得到 true negatives(真 negatives), false positives(假 positives), false negatives(假 negatives) 和 true positives(真 positives) 的数量如下:

1
2
3
4
from sklearn.metrics import confusion_matrix
y_true = [2, 0, 2, 2, 0, 1]
y_pred = [0, 0, 2, 2, 0, 2]
confusion_matrix(y_true, y_pred)

5.1.3 召回

召回率又称查全率(Recall),召回率是指分类器分类正确的正样本个数占所有的正样本个数的比例。直观的理解,召回率是指分类器查找所有正样本的能力。举例来说,召回率是指检索出的相关文档数和文档库中所有的相关文档数的比率,衡量的是检索系统的查全率。

计算代码为:

1
2
3
array([[2, 0, 0],
[0, 0, 1],
[1, 0, 2]])

输出为:

精度和召回往往是一对矛盾的变量。一般来说,当精度高时,召回率会偏低;而当召回率高时,精度会偏低。如果按照预测为正例的概率大小进行排序,按照顺序依次进行预测,得到精度和召回,可以绘制一条 P-R 曲线。P-R 图可以直观地展示样本整体的精度和召回的情况。

构造一个高正确率或高召回率的分类器是很容易的,但是很难保证两者同时成立。如果将所有的样例都判为正例,那么召回率达到 100% 同时正确率很低。构建一个同时使正确率和召回率最大的分类器是具有挑战性的。

5.1.4 F1

为了综合考虑精度和召回,也常常用 F1 度量。F1-score 基于精度和召回的调和平均来定义,它的值更接近于 Precision 与 Recall 中较小的值。其计算方法为:

其中,P 为准确率,R 为召回率。精确率和准确率都高的情况下,F1 值也会高。P 和 R 指标有时候会出现的矛盾的情况,这样就需要综合考虑他们。F1-score 值达到其最佳值 1 ,其最差分数为 0 。

除了 F1 之外,还有一个更普遍的计算公式:
F- = (α^2+1) PR/(α^2)P + R)

也可以直接利用 sklearn 里的函数计算 F1-score:

1
2
3
4
from sklearn.metrics import recall_score
y_true = [0, 1, 2, 0, 1, 2]
y_pred = [0, 2, 1, 0, 0, 1]
recall_score(y_true, y_pred, average='macro')

输出为:

公式里的α(α>0)是用于衡量查全率对查准率的相对重要性。当α=1 时即为标准的 F1(基于 P、R 的调和平均);当α>1 时,查全率具有更大的影响;当α<1 时查准率具有更大影响。

其中α=2 和α=0.5 是除了 F1 之外,两个常用的 F-measure:
(1)当α=2,则表示 recall 的影响要大于 precision;
(2)当α=0.5,则表示 precision 的影响要大于 recall.

F1 值在实际应用中较常用。相比于 P、R 的算术平均和几何平均(G-mean),F1 值更重视较小值(不平衡数据下的稀有类),这也说明 F1 对于衡量数据更有利。

5.1.5 ROC

另一个用于分类模型的评价指标的工具是 ROC 曲线(ROC curve),ROC 全称是受试者工作特征(receiver operating characteristic),它最早是在二战期间由电气工程师构建雷达系统时使用过,ROC 曲线最早是运用在军事上,后来逐渐运用到医学领域,此后被引入机器学习领域中。ROC(Receiver Operating Characteristic)与 P-R 曲线类似,按照预测结果对样例进行排序,按照顺序依次进行预测,计算 TPR 和 FPR,并分别以它为横纵坐标作图,这样就得到了 ROC 曲线。TPR 和 FPR 分别定义为:

召回率 TPR(True Positive Rate) =TP/(TP+FN) = a / (a+b)
取伪率 FPR(False Positive Rate) = FP/(FP+TN) = c / (c+d)

ROC 曲线,图片来自维基百科

在图中的 ROC 曲线中,有几条虚线和一条实线。图中的横轴是取伪率(FPR),Y 轴为召回率(TPR)。ROC 曲线给出的是阈值变化时取伪率和召回率的变化情况,左下角的点所对应的是将所有样例判断为反例的情况,而右上角的点对应的则是将所有样例判断为正例的情况。虚线给出的是随机猜测的结果曲线。

取伪率和召回率这两个指标之间相互制约。通俗地来说,即在 TPR 随着 FPR 递增的情况下,谁增长得更快,快多少的问题。TPR 增长得越快,曲线越往上屈,反映了模型的分类性能就越好。在理想的情况下,最佳的分类起应该尽可能的处于左上角,显而易见,最好的分类器便是 FPR=0%,TPR=100%。这就意味着分类器在取伪率很低的同时获得了很高的召回率。例如在垃圾邮件的过滤中,这就相当于过滤掉了所有垃圾邮件,且没有将任何正常邮件误分类为垃圾邮件。但是一般在实践中一个分类器很难会有这么好的效果,即一般 TPR 不等于 1,FPR 不等于 0 的。当正负样本不平衡时,这种模型评价方式比起一般的精确度评价方式的好处尤其显著。

如何描绘 ROC 曲线?如在二分类中,我们需要设定一个阈值,大于阈值分类正类,否则分为负类。因此,我们可以变化阈值,根据不同的阈值进行分类,根据分类结果计算得到 ROC 空间中的一些点,连接这些点就形成 ROC 曲线。ROC 曲线会经过 (0,0) 与(1,1)这两点,实际上这两点的连线形成的 ROC 代表一个随机分类器,一般情况下分类器的 ROC 曲线会在这条对角连线上方。

实际上,通过有限实例产生的 ROC 曲线实际上是一个阶梯函数,该曲线近似于实例数量接近无限时对应的 ROC 曲线。对模型进行评价时,若某 ROC 曲线可以将另一条 ROC 曲线完全包裹,则可以说明效果要好于被包裹的 ROC 曲线,否则,若两条 ROC 曲线存在交叉,则很难评价哪一条曲线更优。

ROC 曲线有个很好的特性:当测试集中的正负样本的分布变化的时候,ROC 曲线能够保持不变。在实际的数据集中经常会出现类不平衡(class imbalance)现象,即负样本比正样本多很多(或者相反),而且测试数据中的正负样本的分布也可能随着时间变化。与 F1 score 的指标相比, ROC 不需要优化每个标签的阈值。

ROC 曲线是通过与参照线进行比较来判断模型的好坏,虽然很直观好用,但这只是一种直觉上的定性分析,当使用 ROC 曲线对分类器进行评价时,如果对多个分类器进行比较时,如果直接使用 ROC 曲线很难去比较,只能通过将 ROC 分别画出来,然后进行肉眼比较,那么这种方法是非常不便的,因此我们需要一种定量的指标去比较,这个指标便是 AUC 了,即 ROC 曲线下的面积,面积越大,分类器的效果越好,AUC 的值介于 0.5 到 1.0 之间。

AUC(area under curve)即 ROC 曲线下的面积。其含义是随机给定一个正样本和一个负样本,分类器输出该正样本为正的那个概率值比分类器输出该负样本为正的那个概率值要大的可能性。

假设分类器的输出是样本属于正类的 socre(置信度),则 AUC 的物理意义为,任取一对(正、负)样本,正样本的 score 大于负样本的 score 的概率。为了计算 AUC,我们通常是对 ROC 曲线中的多个小矩形的面积进行累加。

计算 AUC 可以直接调用 sklearn:

1
0.33...

可得计算结果:

通常,AUC 的值介于 0.5 到 1.0 之间,较大的 AUC 代表了较好的 performance。一个完美的分类器的 AUC 为 1.0。
当 0.5<AUC<1,优于随机猜测。这个分类器(模型)妥善设定阈值的话,能有预测价值。
当 AUC=0.5,跟随机猜测效果差不多,模型没有预测价值。

ROC 曲线和 AUC 的优势:不受类分布的影响,适合与评估、比较类分布不平衡的数据集。因此 ROC 曲线与 AUC 已被广泛用于医疗决策制定、模式识别和数据挖掘等领域。但是 ROC 和 AUC 仅适合于两类问题 , 对多类问题 , 无法直接应用。

基尼系数应大于 60%,就算好模型。基尼系数经常用于分类问题,其可以直接从 AUC 中得到。其公式为:Gini = 2*AUC - 1

5.1.6 回归模型评价指标

回归是对连续的实数值进行预测,即输出值是连续的实数值,而分类中是离散值。常用的回归模型的评价指标主要有均方误差根(RMSE)和 R - 平方(R2)。

RMSE(root mean square error),其又被称为 RMSD(root mean square deviation),是预测值与真实值的误差平方根的均值。其定义如下:

其中,yi 是真实值,yi^ 是预测值,n 是样本数量,使用了欧式距离。

RMSE 的缺点是:对异常点较敏感,如果回归器对某个点的回归值很不理性,那么它的误差则较大,从而会对 RMSE 的值有较大影响,即平均值是非 Robust 的。

其 python 实现代码如下:

1
2
3
4
from sklearn.metrics import f1_score
y_true = [0, 1, 2, 0, 1, 2]
y_pred = [0, 2, 1, 0, 0, 1]
f1_score(y_true, y_pred, average='macro')

R2_score 是多元回归中的回归平方和占总平方和的比例,它是度量多元回归方程中拟合程度的一个统计量,反映了在因变量 y 的变差中被估计的回归方程所解释的比例。其定义是:

其区间通常在(0,1)之间。0 表示不如均值。1 表示完美预测。R 平方越接近 1,表明回归平方和占总平方和的比例越大,回归线与各观测点越接近,用 x 的变化来解释 y 值变差的部分就越多,回归的拟合程度就越好。

1
0.26666666666666666

5.2 应用

评价方法在很多 python 包中都有已经写好的函数,以下是 Scikit-learn 中对应的函数名称以及描述:

指标 描述 Scikit-learn 函数
Precision 精准度 from sklearn.metrics import precision_score
Recall 召回率 from sklearn.metrics import recall_score
F1 F1 值 from sklearn.metrics import f1_score
Confusion Matrix 混淆矩阵 from sklearn.metrics import confusion_matrix
ROC ROC 曲线 from sklearn.metrics import roc
AUC ROC 曲线下的面积 from sklearn.metrics import auc

Scikit-learn 还允许在 GridSearchCV, RandomizedSearchCV 和 cross_validate 中评估 multiple metric (多个指数)。

接下来我们将对分类模型评价方法进行一个简单的应用。

5.2.1 Iris 多分类

此案例选取的是著名的 Iris 数据集,建立了一个分类模型,该模型绘制了 ROC 曲线,运用了 AUC 评价指标。同时,为了更好地对其他评价指标进行学习,我们也在此模型中对其他评价指标进行了练习。

所使用的数据集是 Iris 数据集,这是机器学习中常用的分类实验数据集,由 Fisher 在 1936 年收集整理。Iris 也称鸢尾花卉数据集,包含 150 个数据集,分为 3 类,每类 50 个数据,每个数据包含 4 个属性。可通过花萼长度,花萼宽度,花瓣长度,花瓣宽度 4 个属性预测鸢尾花卉属于(Setosa,Versicolour,Virginica)三个种类中的哪一类。

先导入 iris 数据集,可以直接从 sklearn 里的 datasets 中加载。

1
2
3
4
5
6
7
import numpy as np
from sklearn import metrics

y = np.array([1,1,2,2])
pred = np.array([0.1,0.4,0.35,0.8])
fpr,tpr,thresholds = metrics.roc_curve(y,pred,pos_label=2)
metrics.auc(fpr,tpr)

若是将 X,y 打印出来,可以看到 X 是一组二维的数组,而 y 是一维数组,且 y 中包含着三种标签。输出为:

1
0.75

我们在加载数据集之后,加入一些随机数来增加训练集中的噪声以增加分类难度。

1
2
3
import math
def rmse(y_test, y):
return math.sqrt(math.mean((y_test - y) ** 2))

对训练集与测试集进行分割,并且打乱。

1
2
def R2(y_test, y_true): 
return 1 - ((y_test - y_true)**2).sum() / ((y_true - y_true.mean())**2).sum()

我们构建一个简单的分类器,即 svm,对鸢尾花的特征来进行分类。先利用 train_test_split 切割训练集和测试集并打乱排序,将分类器预测的标签记为 y_score。

1
2
3
4
5
6
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target
print X
print y

接下来就可以对预测所得到的结果进行评价,我们依次计算这个分类结果的准确率、召回率、F1-score、AUC,并且绘制 ROC 曲线。先计算模型准确率,accuracy_score 这个函数可以帮助我们计算,只需要输入 y 的真实标签的预测标签两个变量即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
X = array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
[5. , 3.6, 1.4, 0.2],
[5.4, 3.9, 1.7, 0.4],
[4.6, 3.4, 1.4, 0.3],
[5. , 3.4, 1.5, 0.2],
[4.4, 2.9, 1.4, 0.2],
[4.9, 3.1, 1.5, 0.1],
[5.4, 3.7, 1.5, 0.2],
[4.8, 3.4, 1.6, 0.2],
[4.8, 3. , 1.4, 0.1]
……
y = array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])

输出为:

1
2
3
4
import numpy as np
random_state = np.random.RandomState(1)
n_samples, n_features = X.shape
X = np.c_[X, random_state.randn(n_samples, 200 * n_features)]

计算模型召回率、F1-score 和 AUC,召回率和 F1-score 的计算都很简单,与准确率的计算类似,但是 AUC 需要先计算取伪率和召回率。

1
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.3,random_state=0)

输出为:

1
2
3
4
5
6
from sklearn import svm
from sklearn.multiclass import OneVsRestClassifier

classifier = OneVsRestClassifier(svm.SVC(kernel='linear', probability=True,random_state=random_state))
y_score = classifier.fit(X_train, y_train).decision_function(X_test)
y_pred = classifier.predict(X_test)

接下来绘制 ROC 曲线。figsize 参数指绘图对象的宽度和高度,在循环中调用 plt.plot 是为了各个分类离的 ROC 曲线,其中,fpr 和 tpr 即取伪率和召回率,分别是 ROC 曲线的横坐标和纵坐标,label 为图例。第二次调用 plt.plot 是为了绘制随机猜测的结果曲线,便于对比 ROC 结果。xlabel 和 ylabel 分别是横纵坐标名,title 为图片名称。

1
2
3
from sklearn.metrics import accuracy_score
y_pred = svm.predict(X_test)
print ('accuracy is %s'%accuracy_score(y_true, y_pred))

结果如图,ROC 曲线离虚线(即随机猜测的结果曲线)越远,则 AUC 越大。

最后附上完整代码

1
accuracy is 0.3111111111111111

5.2.2 多类 AdBoost 决策树

此实例是通过随机生成的数据集,目的在于对两种迭代算法 SAMME.R 算法和 SAMME 算法进行比较,此处我们对于该模型的评价标准选取的是错误率,即 1 - 准确率。

首先我们载入需要的类库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score

print('precision is %s'%svm.score(X_train, y_train))
print ('recall is %s'%recall_score(y_true, y_pred, average='macro'))
print ('F1-score is %s'%f1_score(y_true, y_pred, average='macro') )
# 计算ROC曲线,并且为每一个分类计算AUC
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])
roc_auc[i] = auc(fpr[i], tpr[i])
print ('第%i种分类的roc:%f'%(i,roc_auc[i]))

这次的数据集是通过随机生成一些随机数据,来做二元分类。make_gaussian_quantiles 函数是通过采取多维标准正态分布和定义由嵌套同心多维球分离的类,生成分组多维正态分布的数据。我们共生成 13000 个样本,其中数据有 10 个样本特征,数据类别为 3 类。

1
2
3
4
5
6
precision is 1.0
recall is 0.3737373737373737
F1-score is 0.4809941520467836
0种分类的roc:0.952586
1种分类的roc:0.598765
2种分类的roc:0.775401

将数据分割成训练集和测试集。其中 3000 个为训练集样本,10000 个为测试集样本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib.pyplot as plt

colors = cycle(['aqua', 'darkorange', 'cornflowerblue'])
for i, color in zip(range(n_classes), colors):
plt.plot(fpr[i], tpr[i], color=color, lw=lw,
label='ROC curve of class {0} (area = {1:0.2f})'
''.format(i, roc_auc[i]))

plt.plot([0, 1], [0, 1], 'k--', lw=lw)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Some extension of Receiver operating characteristic to multi-class')
plt.legend(loc="lower right")
plt.show()

Adaboost 是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器,然后把这些弱分类器集合起来,构成一个更强的最终分类器,即强分类器。AdaBoostClassifier 是 sklearn 中一个 AdaBoost 的分类框架,除了 AdaBoostClassifier,AdaBoostRegressor 用于回归。

这里我们分别选择了 SAMME.R 算法和 SAMME 算法,最多 600 个弱分类器,学习率分别是 1 和 1.5。SAMME.R 使用概率估计来更新模型,而 SAMME 仅仅使用分类。

训练模型并记录模型的错误率(1 - 准确率)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import numpy as np
import matplotlib.pyplot as plt
from itertools import cycle

from sklearn import svm, datasets
from sklearn.metrics import roc_curve, auc
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
from scipy import interp

#import sklearn里计算模型评价指标的相关函数



# 导入iris数据集
iris = datasets.load_iris()
X = iris.data
y = iris.target

# 将标签二值化
y = label_binarize(y, classes=[0, 1, 2])
n_classes = y.shape[1]

#向数据集中加入噪声,增加分类的难度
random_state = np.random.RandomState(0)
n_samples, n_features = X.shape
X = np.c_[X, random_state.randn(n_samples, 200 * n_features)]

# 将训练集和测试集打乱
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.3,
random_state=0)

# 构造一个简单的svm分类器
classifier = OneVsRestClassifier(svm.SVC(kernel='linear', probability=True,
random_state=random_state))
#通过decision_function()计算得到的y_score的值,用在roc_curve()函数中
y_score = classifier.fit(X_train, y_train).decision_function(X_test)

y_pred = classifier.predict(X_test)

# 计算准确率
print ('accuracy is %s'%accuracy_score(y_test, y_pred))

# 计算精度
print('precision is %s'%classifier.score(X_train, y_train))

# 计算召回率
print ('recall is %s'%recall_score(y_test, y_pred, average='macro'))

# 计算f1-score
print ('F1-score is %s'%f1_score(y_test, y_pred, average='macro') )


# 计算ROC曲线,并且为每一个分类计算AUC
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
# 计算取伪率和召回率
fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])
# 计算auc的值
roc_auc[i] = auc(fpr[i], tpr[i])
print ('第%i种分类的roc:%f'%(i,roc_auc[i]))


# 绘制所有AUC曲线
colors = cycle(['aqua', 'darkorange', 'cornflowerblue'])
for i, color in zip(range(n_classes), colors):
plt.plot(fpr[i], tpr[i], color=color, lw=lw,
label='ROC curve of class {0} (area = {1:0.2f})'
''.format(i, roc_auc[i]))

plt.plot([0, 1], [0, 1], 'k--', lw=lw)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Some extension of Receiver operating characteristic to multi-class')
plt.legend(loc="lower right")
plt.show()

分别绘制 SAMME.R 算法和 SAMME 算法关于测试集错误率,训练集错误率,以及权重关于树的个数的变化图。figsize 参数为绘制图像的像素大小。

1
2
3
4
5
6
7
8
from sklearn.externals.six.moves import zip

import matplotlib.pyplot as plt

from sklearn.datasets import make_gaussian_quantiles
from sklearn.ensemble import AdaBoostClassifier
from sklearn.metrics import accuracy_score
from sklearn.tree import DecisionTreeClassifier

代码运行结果:

如图所示,SAMME.R 算法收敛速度比 SAMME 更快,在较低的迭代次数下实现了较低的测试误差。每一个 boosting 迭代后的测试集上的每个算法的误差都显示在左边,每个树的测试集上的分类错误在中间显示,并且在右边显示每个树的提升权重。所有的树在 SAMM.R 算法中都有一个权重,因此没有示出。

5.3.3 模型概率校准

执行分类时,我们常常希望不仅可以预测类标签,还要获得相应标签的概率。这个概率可以给我们一些预测的信心。一些模型可以提供部分的概率估计,有些模型甚至不支持概率预测。校准模块可以帮助我们更好地校准给定模型的概率,或者添加对概率预测的支持。该模型综合考虑了精度,召回率以及 F1-score。

首先导入模型所需的包。

1
2
X, y = make_gaussian_quantiles(n_samples=13000, n_features=10,
n_classes=3, random_state=1)

实验在人工数据集上进行二分类,使用 make_classification 函数创建一个足够大的且特征较少的数据集,有 100000 个样本(其中有 1000 个样本用于模型训练),每个样本有 20 个样本特征,有 10 个冗余特征数,只有 2 个是具有信息的特征数。数据集利用 train_test_split 函数进行分割。

1
2
3
4
n_split = 3000

X_train, X_test = X[:n_split], X[n_split:]
y_train, y_test = y[:n_split], y[n_split:]

绘制校准曲线。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
bdt_real = AdaBoostClassifier(
DecisionTreeClassifier(max_depth=2),
n_estimators=600,
learning_rate=1)

bdt_discrete = AdaBoostClassifier(
DecisionTreeClassifier(max_depth=2),
n_estimators=600,
learning_rate=1.5,
algorithm="SAMME")

bdt_real.fit(X_train, y_train)
bdt_discrete.fit(X_train, y_train)

real_test_errors = []
discrete_test_errors = []

for real_test_predict, discrete_train_predict in zip(
bdt_real.staged_predict(X_test), bdt_discrete.staged_predict(X_test)):
real_test_errors.append(
1. - accuracy_score(real_test_predict, y_test))
discrete_test_errors.append(
1. - accuracy_score(discrete_train_predict, y_test))

n_trees_discrete = len(bdt_discrete)
n_trees_real = len(bdt_real)

discrete_estimator_errors = bdt_discrete.estimator_errors_[:n_trees_discrete]
real_estimator_errors = bdt_real.estimator_errors_[:n_trees_real]
discrete_estimator_weights = bdt_discrete.estimator_weights_[:n_trees_discrete]

各个模型输出结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
plt.figure(figsize=(15, 5))

plt.subplot(131)
plt.plot(range(1, n_trees_discrete + 1),
discrete_test_errors, c='black', label='SAMME')
plt.plot(range(1, n_trees_real + 1),
real_test_errors, c='black',
linestyle='dashed', label='SAMME.R')
plt.legend()
plt.ylim(0.18, 0.62)
plt.ylabel('Test Error')
plt.xlabel('Number of Trees')

plt.subplot(132)
plt.plot(range(1, n_trees_discrete + 1), discrete_estimator_errors,
"b", label='SAMME', alpha=.5)
plt.plot(range(1, n_trees_real + 1), real_estimator_errors,
"r", label='SAMME.R', alpha=.5)
plt.legend()
plt.ylabel('Error')
plt.xlabel('Number of Trees')
plt.ylim((.2,
max(real_estimator_errors.max(),
discrete_estimator_errors.max()) * 1.2))
plt.xlim((-20, len(bdt_discrete) + 20))

plt.subplot(133)
plt.plot(range(1, n_trees_discrete + 1), discrete_estimator_weights,
"b", label='SAMME')
plt.legend()
plt.ylabel('Weight')
plt.xlabel('Number of Trees')
plt.ylim((0, discrete_estimator_weights.max() * 1.2))
plt.xlim((-20, n_trees_discrete + 20))

# prevent overlapping y-axis labels
plt.subplots_adjust(wspace=0.25)
plt.show()

第一个图显示了用 Logistic 回归、高斯朴素贝叶斯和高斯朴素贝叶斯得到的估计概率,同时具有等渗校正和乙状结肠校正。这里可以观察到,逻辑回归被很好地校准,因为其曲线几乎是对角线。可以看出,高斯朴素贝叶斯的表现非常差,但是以线性 SVC 的方式也是如此. 尽管线性 SVC 显示了 sigmoid 校准曲线,但高斯朴素贝叶斯校准曲线具有转置的 sigmoid 结构。在这种情况下,分类器的过度自信是由违反朴素贝叶斯特征独立假设的冗余特征引起的。

第二个图显示了线性支持向量分类器(线性 SVC)的校准曲线。线性 SVC 显示了与高斯朴素贝叶斯相反的行为:线性 SVC 的校准曲线或可靠性图具有 sigmoid 曲线,这是一个典型的不够自信的分类器。在 LinearSVC 的情况下,这是 hinge loss 的边缘属性引起的,这使得模型集中在靠近决策边界(支持向量)的 hard samples(硬样本)上。这两种校准都可以解决这个问题,并产生几乎相同的结果。下图显示了高斯朴素贝叶斯在相同数据上的校准曲线,具有两种校准,也没有校准。