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

简介: 在前面的章节中,我们学习了用于分类的基本机器学习算法以及如何在喂给这些算法前处理好数据。下面该学习通过调优算法和评估模型表现来构建良好机器学习模型的最佳实践了。本章中,我们将学习如下内容:评估机器学习模型表现诊断机器学习算法常见问题调优机器学习模型使用不同的性能指标评估预测模型通过管道流程化工作流

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

在前面的章节中,我们学习了用于分类的基本机器学习算法以及如何在喂给这些算法前处理好数据。下面该学习通过调优算法和评估模型表现来构建良好机器学习模型的最佳实践了。本章中,我们将学习如下内容:

  • 评估机器学习模型表现
  • 诊断机器学习算法常见问题
  • 调优机器学习模型
  • 使用不同的性能指标评估预测模型

通过管道流程化工作流

在前面章节中应用不同预处理技术时,比如第4章 构建优秀的训练数据集 – 数据预处理中用于特征缩放的标准化,或第5章 通过降维压缩数据中用于数据压缩的主成分分析,我们学习到需要复用在拟合训练数据缩放及压缩新数据时的参数,比如对分离测试集中的样本。本节中,我们会学习极其趁手的工具,scikit-learn中的Pipeline类。它让我们可以拟合包含任意数量变换步骤的模型并将其用于预测新数据。

加载威斯康星州乳腺癌数据集

本章中,我们会使用威斯康星州乳腺癌数据集,包含有569个恶性和良性肿瘤细胞的样本。数据集中的前两列分别存储样本的唯一ID和对应的诊断结果(M = 恶性, B = 良性)。3-32列包含30个通过细胞核数字化图像计算的真实值特征,可用于构建模型预测肿瘤是良性的还是恶性的。威斯康星州乳腺癌数据集存储在UCI机器学习库中,有关数据集更详细的信息请见https://archive.ics.uci.edu/ml/datasets/Breast+Cancer+Wisconsin+(Diagnostic)

获取威斯康星州乳腺癌数据集

可以在本书代码库中找到一份本数据集(以及本书中使用的其它数据集)的拷贝,以防读者离线操作或是UCI服务器上https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data临时掉线。比如我们从本地目录加载数据集,只需将如下行:

df = pd.read_csv(
    'https://archive.ics.uci.edu/ml/'
    'machine-learning-databases'
    '/breast-cancer-wisconsin/wdbc.data',
    header=None
)

替换为:

df = pd.read_csv(
    'your/local/path/to/wine.data',
    header=None
)

本节中,我们会读取数据集并分3步将其分成训练集和测试集:

  1. 我们先使用pandas直接从UCI网站上读取数据数据集:
```
>>> import pandas as pd
>>> df = pd.read_csv('https://archive.ics.uci.edu/ml/'
...                  'machine-learning-databases'
...                  '/breast-cancer-wisconsin/wdbc.data',
...                  header=None)
```
  1. 接着将30个特征赋给NumPy数组X。使用对象LabelEncoder,我们将原字符串形式的类标签('M''B')转换成整数:
```
>>> from sklearn.preprocessing import LabelEncoder
>>> X = df.loc[:, 2:].values
>>> y = df.loc[:, 1].values
>>> le = LabelEncoder()
>>> y = le.fit_transform(y)
>>> le.classes_
array(['B', 'M'], dtype=object)
```
  1. 在将类标签(诊断结果)编码到数组y中后,恶性肿瘤以类1进行表示,良性肿瘤以类0进行表示。可以对手动添加的类标签调用拟合的LabelEncoder中的transform方法进行映射的验证:
```
>>> le.transform(['M', 'B'])
array([1, 0])
```
  1. 在进入下一小节构建第一个模型管道前,我们将数据集分成训练集(占数据的80%)和单独的测试集(占数据的20%):
```
>>> from sklearn.model_selection import train_test_split
>>> X_train, X_test, y_train, y_test = \
...     train_test_split(X, y,
...                      test_size=0.20,
...                      stratify=y,
...                      random_state=1)
```

在管道中组合转换器和评估器

在前一章中,我们学习很多学习算法要求输入特征处于同一量级来获取最优性能。因威斯康星州乳腺癌数据集用不同的量级度量,我们要在将其喂给逻辑回归等线性分类器前标准化其中的列。此外,我们假定通过主成分分析(PCA)将数据由初始的30维压缩到二维子空间,这一用于维度下降的特征提取技术在第5章中进行过介绍。

这里就不再单独对训练集和测试集做模型拟合与数据变换了,而是在管道中串起StandardScalerPCALogisticRegression对象:

>>> from sklearn.preprocessing import StandardScaler
>>> from sklearn.decomposition import PCA
>>> from sklearn.linear_model import LogisticRegression
>>> from sklearn.pipeline import make_pipeline
>>> pipe_lr = make_pipeline(StandardScaler(),
...                         PCA(n_components=2),
...                         LogisticRegression())
>>> pipe_lr.fit(X_train, y_train)
>>> y_pred = pipe_lr.predict(X_test)
>>> test_acc = pipe_lr.score(X_test, y_test)
>>> print(f'Test accuracy: {test_acc:.3f}')
Test accuracy: 0.956

make_pipeline函数可接收任意数量的scikit-learn转换器(支持fittransform方法作为输入的对象),后接实现了fitpredict方法的scikit-learn评估器。在前面的示例代码中,我们提供了两个scikit-learn转换器StandardScalerPCA,另有一个LogisticRegression评估器作为make_pipeline函数的输入,通过这些对象构建了一个scikit-learn Pipeline对象。

可以把scikit-learn的Pipeline看成是元估计器或对独立转换器和评估器的封装。如果调用Pipelinefit方法,数据会通过对中间步骤调用fittransform传递给一系列转换器,直至到达估计器对象(管道中的最后一个元素)。然后评估器对变换后的训练数据进行拟合。

上例中对pipe_lr管道执行fit方法时,首先StandardScaler对训练数据调用fittransform。然后将变换后的数据传入管道中的下一个对象PCA。类似前一步,PCA也对缩放后的输入数据执行fittransform,然后传递给管道中的最一个元素,估计器。

最后,训练数据在经过StandardScalerPCA的变换后使用LogisticRegression估计器进行拟合。同样,我们应注意对管道的中间步数是没有限制的,如果希望使用管道做预测任务,最后一个管道元素就要是估计器。

与对管道调用fit相似,如果其最后一步是估计器的话管道还实现了一个predict方法。如果将数据集喂给Pipeline对象实例的predict调用,数据会通过transform调用在中间步骤间传递。最后一步,估计器会返回对变换数据的预测。

scikit-learn库的管道是很强大的封装工具,在本书后续会频繁使用到。为确保诸君很好地掌握了Pipeline对象原理,请仔细看图6.1,图中总结 了前面的讨论:

图6.1:管道对象的内部工作原理

图6.1:管道对象的内部工作原理

使用k-折交叉难评估模型表现

本节中,我们会学习常见的交叉验证技术holdout交叉验证和k-折交叉验证,可帮助我们获取模型泛化表现可靠的预估,也就是对未见数据的模型表现。

holdout方法

评估机器学习模型泛化性能的经典且流行的方式是holdout方法。使用holdout方法,我们将初始数据集分成训练集和测试集,前者用于模型训练,后者用于评估泛化性能。但,在典型的机器学习应用中,我们还会调优和比较不同的参数配置以进一步提升未见数据预测的表现。这一过程称为模型选择,这一名称是指我们对给定分类问题我们希望选择调优参数(超参数)最优值。但如果在模型选择期间反复地复用同一测试集,那它就会变成训练集的一部分,进而模型更有可能变得过拟合。虽然有这问题,很多人仍会使用测试集来做模型实践,这并不是一种好的机器学习实践。

使用holdout方法做模型选择更好的方式是将数据分成三个部分:训练集、验证集和测试集。训练集用于拟合不同模型,然后使用验证集的表现做模型选择。测试集的优势是模型在训练和模型选择阶段未见过这部分数据,这样所获取的对新数据的泛化能力的评估偏置更小。图6.2描绘了holdout交叉难的概念,其中我们在通过不同超参数值训练后使用验证集反复评估模型的表现。一旦对超参数值达到满意程度,就开始对测试集评估模型泛化表现:

图6.2:如何使用训练集、验证集和测试集

图6.2:如何使用训练集、验证集和测试集

holdout方法的一个缺点是其性能评估对如何将训练数据集分成训练和验证子集极其敏感,评估随数据样本的不同而不同。在下一小节中,我们会学习更健壮的性能评估技术,k-折交叉验证,其中我们对训练数据的k个子集重复k次holdout方法。

K-折交叉验证

在k-折交叉验证中,我们随机将训练数据集无放回的分成k部分。此处的 k – 1 个折叠,也称为训练折叠,用于做模型训练,而1折叠又称为测试折叠,用于做性能评估。重复这一流程k次,这们便获取了k个模型及性能评估。

有放回和无放回采样

我们在第3章中学习过一个演示有放回和无放回采样的示例。如果读者尚未读取该章或是要复习一下,请参阅通过随机森林组合多个决策树一节中的有放回和无放回抽样补充信息。

然后我们根据不同的独立折叠获取相对holdout方法对测试数据子区分区不那么敏感的性能评估,计算模型的平均性能。通常我们使用k-折交叉验证做模型调优,也即找到产生满意泛化性能的最优超参数值,通过对测试折叠评估模型表现来进行评估。

一旦找到满意的超参数值,就可以对完整训练数据集重新训练模型并使用独立测试数据集获取最终的性能评估。在k-折交叉验证后对整个训练数据集拟合模型的根本原因是,首先我们一般感兴趣的是单个最终模型(对比k个单独模型),其次提供更多的训练样本来学习算法一般能产生更精确、健壮的模型。

因k-折交叉验证是一种无放回的重采样技术,其优势是在每次迭代中,每个样本都只会用到一次,训练和测试部分是无关的。此外,所有测试折叠之间也不相关,也即测试折叠没有重叠部分。图6.3总结了k = 10的k-折交叉验证概念。训练数据集划分为10个部分,在10次迭代中,9个部分用于训练,一个部分用作模型评估的训练数据集。

并且每个部分的预估性能Ei (比如,分类准确度或错误率)之后用于计算评估模型的平均性能E

图6.3:k-折交叉验证的原理

图6.3:k-折交叉验证的原理

总之,k-折交叉验证通过校验集比holdout方法更好地使用了数据集,因为k-折交叉验证中所有的数据点都用于了评估。

按经验k-折交叉验证中k的一个很好的标准值是10。比如Ron Kohavi 对真实数据集和各种实验表明10-折交叉验证在偏置和方差间做了最好的权衡(A Study of Cross-Validation and Bootstrap for Accuracy Estimation and Model Selection by Kohavi, Ron, International Joint Conference on Artificial Intelligence (IJCAI) , 14 (12): 1137-43, 1995, **https://www.ijcai.org/Proceedings/95-2/Papers/016.pdf)。

但如果处理的是相对较小的数据集,增加折叠次数会很有用。如果我们增加k的值,每次迭代中会使用更多的训练数据,这会通过平分独立模型评估的泛化性能来逐步降低悲观偏差。但更大的k值也会增加交叉验证算法的运行时并产生更高方差的评估,因为训练折叠彼此更相近。另一方面,如果我们处理的是大数据集,可以选择较小的k值,比如k = 5,这样减少了重复拟合和评估不同折叠模型评估的计算成本,但仍能获得模型平均性能的精准评估。

留一法交叉验证

k-折交叉验证的一种特殊情况是留一法交叉验证 (LOOCV) 。在留一法中,我们会将折叠数量设置为与训练样本数相同(k = n) ,这样每次迭代只有一个训练样本用于测试,在处理非常小的数据集时推荐此法。

对标准k-折交叉验证做部分改进的方法是分层k-折交叉验证,它会产生更好的偏置和方差预估,尤其是针对非均分类,在前面引用的Ron Kohavi论文中也进行了研究。在分层交叉验证中,每个折叠中保存类标签占比以确保各折叠能够代码训练数据集中的类占比,我们使用scikit-learn中的StratifiedKFold迭代器进行讲解:

>>> import numpy as np
>>> from sklearn.model_selection import StratifiedKFold
>>> kfold = StratifiedKFold(n_splits=10).split(X_train, y_train)
>>> scores = []
>>> for k, (train, test) in enumerate(kfold):
...     pipe_lr.fit(X_train[train], y_train[train])
...     score = pipe_lr.score(X_train[test], y_train[test])
...     scores.append(score)
...     print(f'Fold: {k+1:02d}, '
...           f'Class distr.: {np.bincount(y_train[train])}, '
...           f'Acc.: {score:.3f}')
Fold: 01, Class distr.: [256 153], Acc.: 0.935
Fold: 02, Class distr.: [256 153], Acc.: 0.935
Fold: 03, Class distr.: [256 153], Acc.: 0.957
Fold: 04, Class distr.: [256 153], Acc.: 0.957
Fold: 05, Class distr.: [256 153], Acc.: 0.935
Fold: 06, Class distr.: [257 153], Acc.: 0.956
Fold: 07, Class distr.: [257 153], Acc.: 0.978
Fold: 08, Class distr.: [257 153], Acc.: 0.933
Fold: 09, Class distr.: [257 153], Acc.: 0.956
Fold: 10, Class distr.: [257 153], Acc.: 0.956
>>> mean_acc = np.mean(scores)
>>> std_acc = np.std(scores)
>>> print(f'\nCV accuracy: {mean_acc:.3f} +/- {std_acc:.3f}')
CV accuracy: 0.950 +/- 0.014

首先我们使用训练集中的y_train类标签初始化了sklearn.model_selection模块中的StratifiedKFold迭代器,并通过n_splits参数指定了折叠的数量。在使用kfold迭代器遍历k折叠时,我们使用返回的train中的索引拟合本章一开始配置的逻辑回归管道。使用pipe_lr管道,我们保证了每次迭代中样本进行了适当的缩放(比如做标准化)。然后使用test索引来计算模型的精确度打分,用采集的scores列表计算平均准确度和预估的标准差。

虽然以上的示例代码对于讲解k-折交叉验证原理很有用,实际上scikit-learn还实现了一个k-折交叉验证打分器,可更简洁地使用分层k-折交叉验证评估模型:

>>> from sklearn.model_selection import cross_val_score
>>> scores = cross_val_score(estimator=pipe_lr,
...                          X=X_train,
...                          y=y_train,
...                          cv=10,
...                          n_jobs=1)
>>> print(f'CV accuracy scores: {scores}')
CV accuracy scores: [ 0.93478261  0.93478261  0.95652174
                      0.95652174  0.93478261  0.95555556
                      0.97777778  0.93333333  0.95555556
                      0.95555556]
>>> print(f'CV accuracy: {np.mean(scores):.3f} '
...       f'+/- {np.std(scores):.3f}')
CV accuracy: 0.950 +/- 0.014

cross_val_score方法极其有用的特性是可以将不同折叠的评估分发到主机的多个中央处理单元(CPU)上。如果将n_jobs参数设置为1,仅有一个CPU用于评估表现,和前面的StratifiedKFold示例一样。但设置n_jobs=2时,可以将10轮交叉验证分发到两个CPU上(前提是主机上有两个两个CPU),设置n_jobs=-1,会使用主机上的所有可用CPU来进行并行计算。

评估泛化表现

有关泛化表现的方差如何评估交叉验证的详细讨论不在本书范畴内,但读者可参考有关模型评估和交叉验证更全面的文章(Model Evaluation, Model Selection, and Algorithm Selection in Machine Learning by S. Raschka),在https://arxiv.org/abs/1811.12808上有分享。这篇文章讨论了多种交叉验证技术,比如.632和.632+自举重采样交叉验证(bootstrap cross-validation)法。

此外,可在https://www.jmlr.org/papers/v6/markatou05a.html阅读M. Markatou与其他人合著的优秀文章(Analysis of Variance of Cross-validation Estimators of the Generalization Error by M. Markatou, H. Tian, S. Biswas, and G. M. Hripcsak, Journal of Machine Learning Research, 6: 1127-1168, 2005)。

相关文章
|
26天前
|
机器学习/深度学习 数据采集 人工智能
构建高效机器学习模型的五大技巧
【4月更文挑战第7天】 在数据科学迅猛发展的今天,机器学习已成为解决复杂问题的重要工具。然而,构建一个既精确又高效的机器学习模型并非易事。本文将分享五种提升机器学习模型性能的有效技巧,包括数据预处理、特征工程、模型选择、超参数调优以及交叉验证。这些方法不仅能帮助初学者快速提高模型准确度,也为经验丰富的数据科学家提供了进一步提升模型性能的思路。
|
2月前
|
机器学习/深度学习 数据采集 监控
大模型开发:描述一个典型的机器学习项目流程。
机器学习项目涉及问题定义、数据收集、预处理、特征工程、模型选择、训练、评估、优化、部署和监控。每个阶段都是确保模型有效可靠的关键,需要细致操作。
22 0
|
2月前
|
机器学习/深度学习
大模型开发:解释正则化及其在机器学习中的作用。
正则化是防止机器学习过拟合的技术,通过限制模型参数和控制复杂度避免过拟合。它包含L1和L2正则化,前者产生稀疏解,后者适度缩小参数。选择合适的正则化方法和强度对模型性能关键,常用交叉验证评估。
|
2月前
|
机器学习/深度学习 数据采集 算法
构建高效机器学习模型:从数据预处理到模型优化
在机器学习的实践中,构建一个高效的模型并非一蹴而就。本文将深入探讨如何通过精确的数据预处理、合理的特征选择、适当的模型构建以及细致的参数调优来提升模型的性能。我们将讨论数据清洗的重要性,探索特征工程的策略,分析不同算法的适用场景,并分享模型调参的实用技巧。目标是为读者提供一套系统的方法论,以指导他们在构建机器学习模型时能够更加高效和目标明确。
45 3
|
1月前
|
机器学习/深度学习 数据采集 算法
构建高效机器学习模型的最佳实践
【4月更文挑战第3天】在数据驱动的时代,构建高效的机器学习模型已成为解决复杂问题的关键。本文将探讨一系列实用的技术策略,旨在提高模型的性能和泛化能力。我们将从数据预处理、特征工程、模型选择、超参数调优到集成学习等方面进行详细讨论,并通过实例分析展示如何在实践中应用这些策略。
17 1
|
2月前
|
机器学习/深度学习 数据采集 自然语言处理
构建高效机器学习模型:从数据预处理到模型优化
在机器学习的实践中,一个精确且高效的模型是成功解决问题的关键。本文将深入探讨如何从原始数据的收集与处理开始,通过选择合适的算法,再到模型的训练与优化,最终构建出一个高性能的机器学习模型。我们将讨论数据预处理的重要性、特征工程的策略、常用机器学习算法的选择标准以及超参数调整的最佳实践。通过案例分析和技术讲解,本文旨在为读者提供一个清晰的构建高效机器学习模型的蓝图。
|
3天前
|
机器学习/深度学习 算法 Python
【Python机器学习专栏】机器学习中的超参数调优技术
【4月更文挑战第30天】本文探讨了机器学习中超参数调优的重要性,介绍了网格搜索、随机搜索、贝叶斯优化和AutoML等调优方法,并提供了Python中使用`scikit-learn`进行网格搜索的示例。超参数的选择直接影响模型学习和泛化能力,而调优技术能帮助找到最佳组合,提升模型性能。随着AutoML的发展,自动化调参将成为更高效的选择。
|
3天前
|
机器学习/深度学习 PyTorch 算法框架/工具
【Python机器学习专栏】PyTorch在深度学习中的应用
【4月更文挑战第30天】PyTorch是流行的开源深度学习框架,基于动态计算图,易于使用且灵活。它支持张量操作、自动求导、优化器和神经网络模块,适合快速实验和模型训练。PyTorch的优势在于易用性、灵活性、社区支持和高性能(利用GPU加速)。通过Python示例展示了如何构建和训练神经网络。作为一个强大且不断发展的工具,PyTorch适用于各种深度学习任务。
|
15天前
|
机器学习/深度学习 数据可视化 算法
R语言梯度提升机 GBM、支持向量机SVM、正则判别分析RDA模型训练、参数调优化和性能比较可视化分析声纳数据
R语言梯度提升机 GBM、支持向量机SVM、正则判别分析RDA模型训练、参数调优化和性能比较可视化分析声纳数据
35 9
|
15天前
|
机器学习/深度学习 存储 算法
PYTHON集成机器学习:用ADABOOST、决策树、逻辑回归集成模型分类和回归和网格搜索超参数优化
PYTHON集成机器学习:用ADABOOST、决策树、逻辑回归集成模型分类和回归和网格搜索超参数优化
32 7