其它章节内容请见机器学习之PyTorch和Scikit-Learn

检查不同功能评价目标

在前面的章节中,咱们运用猜想准确率来评价各机器学习模型,通常这是用于量化模型体现很有用的目标。但还有其他几个功能目标能够用于衡量模型的相关性,例如准确率、召回率、F1分数和马修斯相关系数(MCC)等。

读取混杂矩阵

在咱们深入评论各评分目标之前,先看一下混杂矩阵,这是一种展示学习算法功能的矩阵。

混杂矩阵是一个简略的方阵,陈述分类器实在(TP)、真负(TN)、假正(FP)和假负(FN)的猜想次数,如图6.9所示:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

图6.9:混杂矩阵

虽然能够经过手动比较实践和猜想类标签来轻松核算这些目标,但scikit-learn供给了一个方便的confusion_matrix函数供咱们运用,如下所示:

>>> from sklearn.metrics import confusion_matrix
>>> pipe_svc.fit(X_train, y_train)
>>> y_pred = pipe_svc.predict(X_test)
>>> confmat = confusion_matrix(y_true=y_test, y_pred=y_pred)
>>> print(confmat)
[[71  1]
[ 2 40]]

执行代码后回来的数组供给了有关分类器在测试数据集上产生的不同类型过错的信息。咱们能够运用Matplotlib的matshow函数将这一信息映射到图6.9中的混杂矩阵图中:

>>> fig, ax = plt.subplots(figsize=(2.5, 2.5))
>>> ax.matshow(confmat, cmap=plt.cm.Blues, alpha=0.3)
>>> for i in range(confmat.shape[0]):
...     for j in range(confmat.shape[1]):
...         ax.text(x=j, y=i, s=confmat[i, j],
...                 va='center', ha='center')
>>> ax.xaxis.set_ticks_position('bottom')
>>> plt.xlabel('Predicted label')
>>> plt.ylabel('True label')
>>> plt.show()

经过以下添加标签的混杂矩阵图,应该能更容易了解成果:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

图6.10:咱们数据的混杂矩阵

假定本例中,类别1(恶性)是正类,咱们的模型别离正确地将71个样本分类为类别0(TN)以及40个样本分类为类别1(TP)。但咱们的模型也过错地将两个属于类别1的样本分类为类别0(FN),而且它猜想有一个样本是恶性,但实践上它是良性肿瘤(FP)。鄙人一末节中,咱们将学习怎么运用这些信息来核算各种过错目标。

猜想过错率(ERR)和准确率(ACC)都供给了关于有多少示例被过错分类的全体信息。过错率能够了解为一切过错猜想的总和除以总猜想次数,而准确率则是正确猜想的总和除以总猜想次数,别离核算如下:

优化分类模型的准确率及召回率

猜想过错率(ERR)和准确率(ACC)都供给了有关多少样本分类过错的全体信息。过错率可看作一切过错猜想的总和除以总猜想次数,而准确率则是正确猜想的总和除以总猜想次数,别离核算如下:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

然后经过过错率直接核算出猜想准确率:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

实在例率(TPR) 和假正例率(FPR) 是对不均衡分类问题尤为有用的功能目标:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

在肿瘤确诊中,咱们更关注对恶性肿瘤的检测,以协助患者进行恰当的医治。但降低误将良性肿瘤分类为恶性肿瘤(FP)也很重要,避免给患者带来不必要的恐慌。与FPR相反,TPR供给了一切阳性样本(P)中正确辨认的阳性(或相关)样本比例的有用信息。

功能目标准确率(PRE)和召回率(REC)与TP和TN率相关,实践上REC与TPR是近义词:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

换句话说,召回率量化了有多少相关记载(阳性样本)被正确辨认为阳性(真阳性)。准确率量化了被猜想为相关(真阳性和假阳性之和)的记载中实践上相关的(真阳性)占多少:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

重新回顾一下恶性肿瘤检测的案例,优化召回率有助于最小化未能检测到恶性肿瘤的几率。但价值是会猜想健康患者(高FP)为恶性肿瘤。而假如优化准确率,咱们侧重患者患有恶性肿瘤时的正确性。但价值是会更频繁地漏掉恶性肿瘤(高FN)。

为了平衡优化PRE和REC的优缺点,运用PRE和REC的谐和均匀数,即所谓的F1分数:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

准确率和召回率的扩展阅览

假如读者对准确率和召回率等不同功能目标的更深入评论感兴趣,请阅览David M. W. Powers的技能陈述Evaluation: From Precision, Recall and F-Factor to ROC, Informedness, Markedness & Correlation,可在arxiv.org/abs/2010.16…上免费阅览。

最终,汇总混杂矩阵的度量目标是MCC,它在生物研讨范畴特别受欢迎。MCC的核算如下:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

与PRE、REC和F1分数不同,MCC的取值范围在-1到1之间,而且它考虑了混杂矩阵的一切元素,例如F1分数不触及TN。虽然MCC值比F1分数更难核算,但它被看作是一种更优异的度量目标,如下文所述:《二元分类评价中马修斯相关系数(MCC)较F1分数和准确率的优势》by D. Chicco and G. Jurman,BMC Genomics,2012年,281-305页,bmcgenomics.biomedcentral.com/articles/10…。

这些评分目标都在scikit-learn中有完成,并能够经过sklearn.metrics模块中导入,如以下代码片段所示:

>>> from sklearn.metrics import precision_score
>>> from sklearn.metrics import recall_score, f1_score
>>> from sklearn.metrics import matthews_corrcoef
>>> pre_val = precision_score(y_true=y_test, y_pred=y_pred)
>>> print(f'Precision: {pre_val:.3f}')
Precision: 0.976
>>> rec_val = recall_score(y_true=y_test, y_pred=y_pred)
>>> print(f'Recall: {rec_val:.3f}')
Recall: 0.952
>>> f1_val = f1_score(y_true=y_test, y_pred=y_pred)
>>> print(f'F1: {f1_val:.3f}')
F1: 0.964
>>> mcc_val = matthews_corrcoef(y_true=y_test, y_pred=y_pred)
>>> print(f'MCC: {mcc_val:.3f}')
MCC: 0.943

此外,在GridSearchCV中,咱们能够设置scoring参数运用与准确率不同的评分目标。能够在scikit-learn.org/stable/modu…上找到scoring参数所接收值的完好列表。

请记住,在scikit-learn中,正类是标记为类别1的类别。假如我想指定其它正类标签,能够运用make_scorer函数构建自己的评分器,然后以参数形式直接供给给GridSearchCVscoring(本例中,运用f1_score作为评价目标):

>>> from sklearn.metrics import make_scorer
>>> c_gamma_range = [0.01, 0.1, 1.0, 10.0]
>>> param_grid = [{'svc__C': c_gamma_range,
...                'svc__kernel': ['linear']},
...               {'svc__C': c_gamma_range,
...                'svc__gamma': c_gamma_range,
...                'svc__kernel': ['rbf']}]
>>> scorer = make_scorer(f1_score, pos_label=0)
>>> gs = GridSearchCV(estimator=pipe_svc,
...                   param_grid=param_grid,
...                   scoring=scorer,
...                   cv=10)
>>> gs = gs.fit(X_train, y_train)
>>> print(gs.best_score_)
0.986202145696
>>> print(gs.best_params_)
{'svc__C': 10.0, 'svc__gamma': 0.01, 'svc__kernel': 'rbf'}

制作ROC曲线

接收者操作特征(Receiver Operating Characteristic,ROC)曲线是根据其在假正率(FPR)和实在率(TPR)挑选分类模型很有用的东西,这些目标经过改动分类器的决议计划阈值来核算。ROC曲线的对角线可了解为随机猜想,对角线以下的分类模型看作比随机猜想还要差。完美的分类器将位于图形的左上角,其TPR为1、FPR为0。基于ROC曲线,咱们能够核算所谓的曲线下面积(ROC AUC),用于描绘分类模型的功能。

类似于ROC曲线,咱们能够对分类器的不同概率阈值核算准确率-召回率曲线。scikit-learn中也完成了制作这些准确率-召回率曲线的函数,参见官方文档scikit-learn.org/stable/modu…。

执行以下示例代码,咱们将制作一个ROC曲线,该分类器仅运用威斯康星州乳腺癌数据会集的两个特征来猜想肿瘤是良性仍是恶性。虽然咱们运用之前界说的逻辑回归管道,但这次只运用两个特征。这样做是为了使分类任务对分类器更具挑战性,经过躲藏其他特征中包括的有用信息,使得到的ROC曲线视觉上更有趣。出于类似的原因,咱们还将StratifiedKFold验证器中的折叠数削减到三。代码如下所示:

>>> from sklearn.metrics import roc_curve, auc
>>> from numpy import interp
>>> pipe_lr = make_pipeline(
...     StandardScaler(),
...     PCA(n_components=2),
...     LogisticRegression(penalty='l2', random_state=1,
...                        solver='lbfgs', C=100.0)
... )
>>> X_train2 = X_train[:, [4, 14]]
>>> cv = list(StratifiedKFold(n_splits=3).split(X_train, y_train))
>>> fig = plt.figure(figsize=(7, 5))
>>> mean_tpr = 0.0
>>> mean_fpr = np.linspace(0, 1, 100)
>>> all_tpr = []
>>> for i, (train, test) in enumerate(cv):
...     probas = pipe_lr.fit(
...         X_train2[train],
...         y_train[train]
...     ).predict_proba(X_train2[test])
...     fpr, tpr, thresholds = roc_curve(y_train[test],
...                                      probas[:, 1],
...                                      pos_label=1)
...     mean_tpr += interp(mean_fpr, fpr, tpr)
...     mean_tpr[0] = 0.0
...     roc_auc = auc(fpr, tpr)
...     plt.plot(fpr,
...              tpr,
...              label=f'ROC fold {i+1} (area = {roc_auc:.2f})')
>>> plt.plot([0, 1],
...          [0, 1],
...          linestyle='--',
...          color=(0.6, 0.6, 0.6),
...          label='Random guessing (area=0.5)')
>>> mean_tpr /= len(cv)
>>> mean_tpr[-1] = 1.0
>>> mean_auc = auc(mean_fpr, mean_tpr)
>>> plt.plot(mean_fpr, mean_tpr, 'k--',
...          label=f'Mean ROC (area = {mean_auc:.2f})', lw=2)
>>> plt.plot([0, 0, 1],
...          [0, 1, 1],
...          linestyle=':',
...          color='black',
...          label='Perfect performance (area=1.0)')
>>> plt.xlim([-0.05, 1.05])
>>> plt.ylim([-0.05, 1.05])
>>> plt.xlabel('False positive rate')
>>> plt.ylabel('True positive rate')
>>> plt.legend(loc='lower right')
>>> plt.show()

在上面的示例代码中,咱们运用了scikit-learn中现已了解的StratifiedKFold类,并在每次迭代中运用sklearn.metrics模块中roc_curve函数核算了pipe_lr流水线中LogisticRegression分类器的ROC功能。此外,咱们运用从NumPy导入的interp函数对三个折叠的均匀ROC曲线进行了插值,并经过auc函数核算了曲线下面积。得到的ROC曲线标明不同折叠之间存在一定的变化,而均匀ROC AUC(0.76)介于完美得分(1.0)和随机猜想(0.5)之间:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

图6.11:ROC曲线图

留意假如只对ROC AUC分数感兴趣,也能够直接从sklearn.metrics子模块中导入roc_auc_score函数,该函数类似于前几节介绍的其他评分函数(例如precision_score)。

将分类器的功能陈述为ROC AUC能够进一步了解分类器在不均衡样本方面的功能。但虽然准确率分数可解释为ROC曲线上的一个截止点,但A. P. Bradley指出ROC AUC和准确率目标大大都状况下是一致的:《ROC曲线下面积在机器学习算法评价中的运用》,A. P. Bradley,《模式辨认》,30(7): 1145-1159, 1997,reader.elsevier.com/reader/sd/p…。

多类分类的评分目标

到目前停止,咱们评论的评分目标都是针对二分类体系的。但是,scikit-learn还完成了一对多(OvA)分类的宏均匀和微均匀办法,将这些评分目标扩展到多类别问题上。微均匀经过体系的独自TP、TN、FP和FN核算得出的。例如,在一个k-类体系中,准确度分数的微均匀核算如下:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

宏均匀可简略地核算为不同体系的均匀分数:

机器学习之PyTorch和Scikit-Learn第6章 学习模型评估和超参数调优的最佳实践Part 3

假如咱们想要均等地权衡每个实例或猜想,微均匀很有用,而宏均匀将一切类别平等加权,以评价分类器对最常见的类标签的全体功能。

在scikit-learn中,假如咱们运用二分类功能目标来评价多类分类模型,默许会运用宏均匀的归一化或加权变种。加权宏均匀经过将每个类标签的得分乘以在核算均匀时的实在实例数来进行加权。假如咱们处理类别不均衡(即不同标签的实例数不同),加权宏均匀很有用。

虽然加权宏均匀是scikit-learn中多类别问题的默许办法,但咱们能够经过从sklearn.metrics模块导入的不同评分函数中的average参数来指定均匀办法,例如precision_scoremake_scorer函数:

>>> pre_scorer = make_scorer(score_func=precision_score,
...                          pos_label=1,
...                          greater_is_better=True,
...                          average='micro')

处理类不平衡

本章中,咱们屡次提到了类不平衡的问题,但实践上还没有评论假如恰当地处理这种状况。类不平衡是在处理实践国际数据时很常见的问题,即数据会集一个类别或多个类别的样本过多。能够设象几个可能会发生这种状况的范畴,例如垃圾邮件过滤、欺诈检测或疾病筛查。

假定咱们在本章中运用的威斯康星乳腺癌数据会集有90%的健康患者。这时,只需对一切样本猜想大都类别(良性肿瘤),而不借助机器学习监督算法,就能够在测试数据集上完成90%的准确率。因而,在这样的数据集上练习模型并完成大约90%的测试准确度意味着咱们的模型没有从该数据集供给的特征中学到任何有用的信息。

本节中,咱们将扼要介绍一些可用于处理不平衡数据集的技能。但在评论处理这个问题的各种办法之前,咱们先从数据会集创立一个不平衡数据集,原始数据会集包括357个良性肿瘤(类0)和212个恶性肿瘤(类1):

>>> X_imb = np.vstack((X[y == 0], X[y == 1][:40]))
>>> y_imb = np.hstack((y[y == 0], y[y == 1][:40]))

在这段代码中,咱们取了一切357个良性肿瘤样本,并与前40个恶性肿瘤样本放在一起,创立了一个显着的类别不平衡。假如咱们核算的模型准确率总是猜想大都类别(良性,类0),就会取得约90%的猜想准确率:

>>> y_pred = np.zeros(y_imb.shape[0])
>>> np.mean(y_pred == y_imb) * 100
89.92443324937027

因而,在对这样的数据集拟合分类器时,与其比较不同模型的准确率,咱们更应该关注其他目标,如准确度、召回率、ROC曲线等,详细取决于咱们在运用中最关怀的内容。例如,咱们的优先级可能是辨认出大大都患有恶性癌症的患者以便推荐额定的筛查,那么召回率应该是咱们挑选的目标。在垃圾邮件过滤中,假如体系不确定咱们便不期望将邮件标记为垃圾邮件,那么准确率可能是更适宜的目标。

除了评价机器学习模型之外,类不平衡还会影响模型拟合过程中的学习算法。由于机器学习算法通常优化拟合过程中核算为练习样本加和的奖赏或丢失函数,决议计划规矩很可能会偏向于大都类别。

换句话说,算法会隐式地学习一个模型,优化基于数据会集最常见类别的猜想,以在练习中最小化丢失或最大化奖赏。

在模型拟合过程中处理类不平衡占比的一种办法是对少量类的过错猜想赋予更大的惩罚。经过scikit-learn,调整这种惩罚十分方便,只需将class_weight参数设置为class_weight='balanced',大大都分类器都完成了这个功能。

处理类不平衡的其他常用战略包括增加少量类别的样本、削减大都类别的样本以及生成组成练习样本。惋惜并没有一种在不同问题范畴中都体现最佳的普适处理方案或技能。因而,在实践中,主张尝试不同的战略,评价成果,并挑选最适宜的技能。

scikit-learn库完成了一个简略的resample函数,能够经过对数据集有放回地抽取新样本来协助增加少量类别的样本。以下代码将从咱们的不均衡的威斯康星州乳腺癌数据会集获取少量类(这里是类1),并反复从中抽取新样本,直到它包括与类标签0相同数量的样本停止:

>>> from sklearn.utils import resample
>>> print('Number of class 1 examples before:',
...       X_imb[y_imb == 1].shape[0])
Number of class 1 examples before: 40
>>> X_upsampled, y_upsampled = resample(
...         X_imb[y_imb == 1],
...         y_imb[y_imb == 1],
...         replace=True,
...         n_samples=X_imb[y_imb == 0].shape[0],
...         random_state=123)
>>> print('Number of class 1 examples after:',
...       X_upsampled.shape[0])
Number of class 1 examples after: 357

重采样后,咱们能够将原始的类0样本与扩充采样的类1子集合并起来,取得一均衡的数据集,代码如下所示:

>>> X_bal = np.vstack((X[y == 0], X_upsampled))
>>> y_bal = np.hstack((y[y == 0], y_upsampled))

因而,运用大都投票猜想规矩只能达到50%的准确率:

>>> y_pred = np.zeros(y_bal.shape[0])
>>> np.mean(y_pred == y_bal) * 100
50

类似地,咱们能够经过从数据会集删除练习样本来削减大都类的采样。运用resample函数缩减采样,咱们只需将此前的示例代码中类1标签与类0交流。

生成新的练习数据以处理类不平衡问题

处理类不平衡的另一种技能是生成组成练习样本,这不在本书的范畴内。用于生成组成练习数据的最常用算法可能是人工少量类过采样法(SMOTE) ,读者能够在Nitesh Chawla等人的原始研讨文章中了解更多该技能的更多信息:《SMOTE: 人工少量类过采样法》,《人工智能研讨学报》,16:321-357,2002年,可在www.jair.org/index.php/j…上获取。也强烈主张检查imbalance-learn,这是一个专注于不平衡数据集的Python库,包括SMOTE的完成。能够在github.com/scikit-lear…上了解更多关于imbalance-learn的信息。

小结

在本章的最初,咱们评论了怎么在方便的模型流水线中链接不同的转化技能和分类器,这有助于咱们更高效地练习和评价机器学习模型。然后,咱们运用这些管道执行了k-折交叉验证,这是模型挑选和评价的重要技能之一。运用k-折交叉验证,咱们制作了学习曲线和验证曲线,来确诊学习算法的常见问题,如过拟合和欠拟合。

运用网格查找、随机查找和successive halving,咱们进一步对模型进行了调优。然后,咱们运用混杂矩阵和各种功能目标来评价和优化模型在特定问题任务上的功能。最终,咱们经过评论处理不平衡数据的各种办法来结束本章,这是许多实践运用中的常见问题。现在,读者应该具有了本钱构建分类监督机器学习模型的根底技能。

下一章中,咱们将学习集成办法:这些办法允许咱们将多个模型和分类算法组合起来,以进一步提升机器学习体系的猜想功能。