在机器学习项目中存在可以自动化的标准工作流。
在 Python scikit-learn 中,Pipelines 有助于清晰地定义和自动化这些工作流。
在本文中,您将了解 scikit-learn 中的 Pipelines 以及如何自动化常见的机器学习工作流。
通过我的新书《Python 机器学习精通》,逐步教程和所有示例的Python 源代码文件,来启动您的项目。
让我们开始吧。
- 2017年1月更新:更新以反映 scikit-learn 0.18 版本中的 API 变化。
- 2018年3月更新:添加了替代链接以下载数据集,因为原始链接似乎已被删除。

使用 Python 和 scikit-learn 中的 Pipeline 自动化机器学习工作流
照片作者:Brian Cantoni,部分权利保留。
用于自动化机器学习工作流的 Pipelines
应用机器学习中存在标准工作流。之所以标准,是因为它们解决了常见问题,例如测试中的数据泄露。
Python scikit-learn 提供了一个 Pipeline 工具来帮助自动化机器学习工作流。
Pipelines 的工作方式是允许将线性数据转换序列链接在一起,最终形成一个可以进行评估的建模过程。
目标是确保管道中的所有步骤都约束在用于评估的数据范围内,例如训练数据集或交叉验证过程的每个折叠。
您可以阅读用户指南中的 Pipeline 部分,以了解更多关于 scikit-learn 中 Pipelines 的信息。您还可以查看 pipeline 模块中 Pipeline 和 FeatureUnion 类的 API 文档。
需要 Python 机器学习方面的帮助吗?
参加我为期 2 周的免费电子邮件课程,探索数据准备、算法等等(附带代码)。
立即点击注册,还将免费获得本课程的 PDF 电子书版本。
Pipeline 1:数据准备和建模
应用机器学习中容易陷入的一个陷阱是将训练数据集中的数据泄露到测试数据集中。
为了避免此陷阱,您需要一个具有严格训练和测试分离的健壮测试框架。这包括数据准备。
数据准备是向算法泄露整个训练数据集知识的一种简单方式。例如,在学习之前使用整个训练数据集进行归一化或标准化来准备数据将不是一个有效的测试,因为训练数据集会受到测试集数据规模的影响。
Pipelines 通过确保标准化等数据准备过程约束在交叉验证过程的每个折叠中,来帮助您防止测试中的数据泄露。
下面的示例演示了这种重要的数据准备和模型评估工作流。管道定义了两个步骤:
- 标准化数据。
- 学习线性判别分析模型。
然后使用 10 折交叉验证来评估管道。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# 创建一个管道,对数据进行标准化,然后创建一个模型 from pandas import read_csv from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline from sklearn.discriminant_analysis import LinearDiscriminantAnalysis # 加载数据 url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = read_csv(url, names=names) array = dataframe.values X = array[:,0:8] Y = array[:,8] # 创建管道 estimators = [] estimators.append(('standardize', StandardScaler())) estimators.append(('lda', LinearDiscriminantAnalysis())) model = Pipeline(estimators) # 评估流水线 seed = 7 kfold = KFold(n_splits=10, random_state=seed) results = cross_val_score(model, X, Y, cv=kfold) print(results.mean()) |
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。可以尝试运行该示例几次,并比较平均结果。
运行该示例将提供该设置在数据集上的准确性摘要。
1 |
0.773462064252 |
Pipeline 2:特征提取和建模
特征提取是另一个容易发生数据泄露的过程。
与数据准备一样,特征提取过程必须限于训练数据集中的数据。
Pipeline 提供了一个名为 FeatureUnion 的便捷工具,该工具允许将多个特征选择和提取过程的结果合并到一个更大的数据集上,然后可以在该数据集上训练模型。重要的是,所有特征提取和特征联合都发生在交叉验证过程的每个折叠中。
下面的示例演示了定义了四个步骤的管道:
- 使用主成分分析进行特征提取(3 个特征)
- 使用统计选择进行特征提取(6 个特征)
- 特征联合
- 学习逻辑回归模型
然后使用 10 折交叉验证来评估管道。
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 |
# 创建一个管道,从数据中提取特征,然后创建一个模型 from pandas import read_csv from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score from sklearn.pipeline import Pipeline from sklearn.pipeline import FeatureUnion from sklearn.linear_model import LogisticRegression 从 sklearn.分解 导入 PCA from sklearn.feature_selection import SelectKBest # 加载数据 url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv" names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class'] dataframe = read_csv(url, names=names) array = dataframe.values X = array[:,0:8] Y = array[:,8] # 创建特征联合 features = [] features.append(('pca', PCA(n_components=3))) features.append(('select_best', SelectKBest(k=6))) feature_union = FeatureUnion(features) # 创建管道 estimators = [] estimators.append(('feature_union', feature_union)) estimators.append(('logistic', LogisticRegression())) model = Pipeline(estimators) # 评估流水线 seed = 7 kfold = KFold(n_splits=10, random_state=seed) results = cross_val_score(model, X, Y, cv=kfold) print(results.mean()) |
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能会有所不同。可以尝试运行该示例几次,并比较平均结果。
运行该示例将提供管道在数据集上的准确性摘要。
1 |
0.776042378674 |
总结
在本文中,您了解了应用机器学习中数据泄露的困难。
您了解了 Python scikit-learn 中的 Pipeline 工具以及如何使用它们来自动化标准的机器学习工作流。
您学会了如何在两个重要用例中使用 Pipelines:
- 数据准备和建模约束在交叉验证过程的每个折叠中。
- 特征提取和特征联合约束在交叉验证过程的每个折叠中。
您对数据泄露、Pipelines 或本文有任何疑问吗?在评论中提问,我会尽力回答。
嗨
谢谢你的好帖子!
当我们使用 pipeline 时,训练数据(9 个折叠)会被标准化,然后用于标准化训练数据的参数会被用来标准化测试数据吗?这篇帖子是这样建议的
http://stats.stackexchange.com/questions/174823/how-to-apply-standardization-normalization-to-train-and-testset-if-prediction-I
谢谢
您能否为我们提供一个使用 pipeline 进行数据准备和特征选择的示例?过采样(ADASYN)也应该仅在训练数据上进行。可以同时进行这三者吗?
非常感谢
谢谢
我在这里找到了答案
http://stats.stackexchange.com/questions/228774/cross-validation-of-a-machine-learning-pipeline
当 Y 有多于一列数据时(替换 Y = array[:,8]),会发生什么?以及如何使用你的方法来做?谢谢 & 此致,Chaks
好问题,预测多个输出的想法。
我没有任何示例,也不确定 sklearn 是否支持此行为。我知道单个算法支持此功能,例如神经网络。
如何在 pipeline 中获取精确率和召回率值?
你好 Chaks,
就像你对任何分类器做的那样。
这个例子可能有助于
https://scikit-learn.cn/stable/auto_examples/model_selection/plot_precision_recall.html
嗨,Jason,
在使用 Keras/Scikit-wrapper 和 Pipeline 进行标准化以获得最佳拟合后,如何访问 Pipeline 中 Keras regressor/classifier 的权重?我想将这些权重打印到文本或 CSV 文件中。但我难以访问这些权重。
Pratik,我不太确定。
您可能需要单独转换数据,并使用独立的 Keras 模型,这样您就可以直接访问权重。
感谢 Jason 的精彩帖子。
为了我的理解。Feature Union 允许我们将两种特征提取方法放入 pipeline 中,它们保持独立,对吗?因为使用 PCA 获取 3 个特征然后选择最好的 6 个特征是没有意义的。但它们是如何组合在一起的?你能详细说明一下,或者推荐一个好的来源吗?
附注:Keras vs tflearn vs Tensorflow?我觉得 Keras 对我这样的初学者来说是最简单的!
谢谢
嗨 Dan,
特征的联合只是将它们添加到一个大的数据集中,作为新的列供您稍后在 pipeline 中使用/处理。
在第二个示例中,为什么不将归一化步骤添加到 pipeline 中;例如
estimators.append(('standardize', StandardScaler()))
从第一个例子中?
当然可以。在第二个示例中,我尝试演示一些除了缩放之外的其他内容。
缩放器是否应该在特征联合之后?
听起来不错。
嗨,Jason!
感谢这篇文章。再一次,这是解开谜题的缺失部分!
您写道“在学习之前使用整个训练数据集进行归一化或标准化在训练之前,不应该是一个有效的测试”。您指的是在分割训练/验证和独立测试集之前对整个数据集进行标准化,是吗?
关于何时何地在监督学习任务中进行数据标准化,是否有更多信息——关于如何避免最常见工作流中的数据泄露的某种流程图?
此致!
理想情况下,所有数据准备都应该仅在训练数据集上或从训练数据集中进行。
我还有更多笔记
https://machinelearning.org.cn/data-leakage-machine-learning/
Jason 的又一篇精彩文章!“预处理或特征提取期间的数据泄露”是一个很少在 ML 课程中涵盖的棘手陷阱……
谢谢你,Franco。
感谢您的精彩帖子和书籍!
如果你要尝试多种模型(例如 LinearRegression、Lasso 和 Ridge),你会为要测试的每个模型重复第一个示例中的第 16-24 行吗?
谢谢你
是的,正是如此。
我对于组合 PC 和选定的最佳特征进行预测感到困惑。主成分是原始特征的组合。对 PCA 和核 PCA 进行特征联合,或者在某些情况下,对逐步和向后选择进行特征联合,是否明智?
这只是一个示例。它可能对您的数据没有意义。
我爱你!(说真的,我是初学者,每次我查找东西时,您的博客都会弹出,并且我都能以令人难以置信的清晰度找到我想要的东西!)
很高兴听到这些材料对 Laura 有帮助。
你好 Jason,很棒的文章。不过我有几个问题。
1) 在文本分类中也适用吗?例如,创建词袋模型,或者更优的 tf-idf 特征,高度依赖于语料库中的所有文档。我的理解是,我们会拟合类似 tf-idf transformer 的模型到训练集上,基于训练数据“学习”idf,并使用相同的 transformer 来转换测试数据(现在使用来自具体测试文档的 tf 和来自训练语料库的“学习”的 idf)来确定准确性。这同样适用于实时进入的新数据。我的理解正确吗?
2) 如果您有训练/测试/验证集划分,您是否仅根据训练数据集确定转换参数,并以相同的方式将其应用于测试集和验证集?
3) 如何将 k 折交叉验证与训练/测试/验证的概念结合起来?您是否只在训练数据集上进行交叉验证,并“减少一个数据集”,例如在训练集(80%)上进行 k 折交叉验证,验证集(20%)用于超参数调优,测试集(20%)用于最终检查?
我希望问题足够清晰,而且数量不多 🙂 再次感谢,这是一篇很棒的文章。
是的,在拟合模型和对新数据进行预测时必须使用相同的转换。
是的,转换仅在用于拟合模型的数据上准备。
也许可以看看这篇关于如何评估模型itié
https://machinelearning.org.cn/difference-test-validation-datasets/
还有这篇文章
https://machinelearning.org.cn/evaluate-skill-deep-learning-models/
我希望这能给你一些扎实的想法。
你好,你为什么拆分测试/验证?
对我来说似乎没有意义。它们不是同一件事吗?
不,它们是不同的。
https://machinelearning.org.cn/difference-test-validation-datasets/
你好,很棒的文章,
将模型摘要(系数、截距等)包含在 pipeline 中的最佳方法是什么?
即使它没有包含在 pipeline 中,您如何访问单个 pipeline 元素以提取相关信息?
好问题。
您可以在将模型添加到 pipeline 使用的列表中之前保留对其的引用。
您能给一个例子以便更好地理解吗?
没有,抱歉。
嗨,Jason,
再次感谢您的所有帖子。它们已经成为我不可或缺的资源。我有一个关于 Pipeline 2:特征提取和建模第 19 行的问题;我们是否遗漏了提及随机状态的种子?我应该用以下内容替换这一行吗?
features.append((‘pca’, PCA(n_components=3, random_state=7)))
Jason,写得太棒了。谢谢!
谢谢,很高兴对您有帮助。
嗨 Jason
我对评分方面感到困惑。如何在使用 pipeline + 交叉验证后对新数据集进行评分?
这是我的例子
estimators = []
estimators.append(('standardize', StandardScaler()))
estimators.append(('mlp', KerasClassifier(build_fn=create_large_model, nb_epoch=250,
validation_split=0.15,batch_size=25, verbose=2)))
pipeline = Pipeline(estimators)
kfold = StratifiedKFold(n_splits=3, shuffle=True, random_state=108)
results = cross_val_score(pipeline, X_train, y_train, cv=kfold)
这可以正常训练模型,但如果我运行以下代码
print(accuracy_score(y_train, pipeline.predict(X_train)))
我收到一个错误
“NotFittedError: 这个 StandardScaler 实例还没有拟合。在使用此方法之前,请先使用适当的参数调用‘fit’。”
我们不对新数据进行评分。
一旦我们选择了模型,我们就可以用所有训练数据拟合一个新模型,然后使用该模型对新数据进行预测。
也许这篇文章会有所帮助
https://machinelearning.org.cn/make-predictions-scikit-learn/
感谢您的快速回复。我错误地使用了“score”这个词。我的意思是,使用交叉验证后的模型在训练集上对新数据进行预测。
据我目前对 pipelining 的理解,任何预处理步骤(如缩放/归一化等)都使用训练数据上的 fit_transform 方法,并保存转换参数,以便在预测新数据(使用 transform 方法)时可以重用它们,或者我是否完全误解了?
我的困惑源于这样一个事实:当我使用了一些预处理步骤在训练数据上,然后将其与 pipeline 中的交叉验证结合使用时,模型权重或参数将在我上面示例的“pipeline”对象中可用,因此它们可以进一步使用。
如果我删除了交叉验证步骤,我就可以使用 pipeline.predict 来获取新数据集的预测。
CV期间准备的所有模型都会被丢弃。CV是为了在未见过的数据上估计模型的性能。
一旦估计完毕,如果我们满意,我们可以拟合最终模型并开始进行预测。这包括所有数据转换。
也许这篇文章会有所帮助
https://machinelearning.org.cn/train-final-machine-learning-model/
Jason你好。首先,感谢您提供的信息丰富的博文,我有一个问题。
假设我们在工作流程中有一些特征缩放。我按照您在这篇文章中描述的那样,使用管道进行交叉验证。最后,我找到了一个让我满意的模型,并用所有训练数据来训练它。
现在,假设我有了新的、从未见过的数据,我想进行一些预测。在进行预测之前,我必须对新数据进行特征缩放。
为了缩放新数据,我应该在我的缩放器中使用什么数据?只使用新数据?训练数据和新数据?还是只使用训练数据?
最好在交叉验证过程的每个折叠中执行特征缩放。
一旦选择了模型,最终模型就会在所有可用数据上拟合,包括为所有可用数据准备缩放转换。当新数据进来时,可以使用相同的转换对象/系数。
建议
编辑以将“...整个训练数据集...”替换为“整个数据集”,否则会让人们混淆,认为训练数据集等同于整个数据集,而事实并非如此,前者包含了测试数据集。
抱歉,我的意思是最后一个也包含了测试数据集。
感谢Daniel的建议。
你好,
很棒的帖子,Json。
我想知道管道的目的是什么,如果我们先将整个数据集进行训练和测试分割,然后对训练集应用预处理步骤,生成的编码器或缩放器对象可以被pickle,然后可以为测试数据集反pickle?
*Jason,非常抱歉拼写错误。
为了自动化数据在建模前正确排序/应用数据转换。
如果您愿意,也可以手动完成。
Jason,正如您提到的“重要的是,所有特征提取和特征联合都发生在交叉验证过程的每个折叠中。”
您能否通过示例来详细说明这一点?因为我正在尝试了解如果我使用5折交叉验证方法,特征提取和特征联合将如何进行?
这是否意味着在K折交叉验证的每次迭代中,您都会获得训练数据的特征列表?这个过程会继续进行其余的迭代,然后您将每个迭代的所有特征组合起来,最终列表是所有特征的联合?
这意味着每次的训练/测试分割都是独立的,并且数据准备的方式可以防止数据泄露。
https://machinelearning.org.cn/data-leakage-machine-learning/
Jason你好,很棒的文章!如果数据中包含一些分类特征,或者我们不想标准化某些数值特征,我们仍然可以在管道中包含StandardScalar吗?还是我们需要单独对所需的特征进行标准化?
最好分开处理。
Jason你好,如果我们保存了管道(包含预处理+标准化+模型),未来是否可以使用它对单个测试记录进行相同的步骤处理?
是的。
在此处了解如何操作
https://machinelearning.org.cn/make-predictions-scikit-learn/
嗨,Jason,
我已经在原始数据上进行了训练测试分割,
使用Xtrain进行了数据预处理并构建了模型,然后保存了管道,
当我将Xtest传递给管道时,出现错误,提示训练集列中的所有类别都不存在于测试集中。
是否应该先进行预处理,然后再构建管道?
谢谢
也许您的测试集与训练数据集不同?
您必须确保训练数据集包含模型在测试/预测中预期会遇到的所有情况。
谢谢Jason,非常感谢您快速回复。
嗨,Jason,
在某个类别列中,例如婚姻状况,我们有级别(已婚、单身、离婚、分居),当我执行get_dummies时,我得到4个虚拟列,使用这些列,我从X_train构建数据预处理和模型管道。
假设在X_test中,婚姻状况只有2种(已婚、单身),当我将它传递给同一个上述管道时,在数据预处理过程中,get_dummies只创建2列,所以模型显示形状错误(因为我们没有其他两列类别)。
请问我该如何处理这个问题?
谢谢
我建议使用标签编码器或独热编码器,并在训练数据集上拟合编码器。
Jason
在您的其他课程中,您提到了在执行线性回归时对输入和目标进行缩放。我可以想象将2个缩放器放入管道,但是如何将一个缩放器应用于输入,而另一个应用于目标?
好问题。我认为它们要么全应用,要么都不应用。
您需要手动对数据的子集执行操作。
Jason你好,感谢您的详细解释。
您能否告诉我ColumnTransformer()和FeatureUnion()方法有什么区别?
FeatureUnion组合列,就像hstack一样。
Column Transformer将对特征子集应用任何任意操作,然后将结果进行hstack。
好的,感谢您的澄清。
不客气。
嗨,Jason,
是否可以将管道用于创建导入和从URL加载数据集的第一步?
请告知。谢谢。
也许可以,如果你自己编写代码的话。
嗨,Jason,
谢谢您的回复。
你能展示一下如何在管道中编写吗?
我很感谢您的帮助。真的。
抱歉,不行。
您是否有任何可以参考的URL来指导我?谢谢。
也许可以尝试在stackoverflow上发布您的问题。
嗨 Jason
我不太明白为什么要在FeatureUnion中使用两个特征提取?PCA的3个分量与SelectKBest的6个选定特征中的3个相同?这是否意味着我们在重复工作?还是模型会先在PCA上训练,然后根据SelectKBest训练?之后它们会相互比较,看看哪个更好?另外,为什么在应用选择方法的组件数量时不选择相等的数量?谢谢
我们不这样做,这只是一个关于如何使用管道的示例。
那么,我们通常应该选择相等的数量吗?
不,您应该选择能够为您的测试评估带来最佳性能的特征数量。
好的,太好了。那么SelectKBest中的6个特征和PCA中的3个特征可能都很好?
您必须使用受控的实验来发现对给定数据集最有效的方法。
嗨,Jason,
Sklearn Pipeline绝对是一个强大的模块!感谢这次介绍。
我根据您的代码进行了一些实验,在此分享我的结果
– 我认为不需要使用FeatureUnion。现有的特征列表可以直接使用。
– 从Pipeline步骤列表中删除FeatureUnion,对logisticRegression模型的得分结果是相同的。因此,我看不出包含这种特征联合的目的是什么……
– 如果在KFold函数中未将shuffle设置为True(如您的情况),则random_state参数将没有意义。
非常感谢您的教程
我的问题
1) Pipeline被用作整个流程的集合,并准备好实现kfold、cross_val_score等。OK。
但是,如果我对了解任何步骤的中间结果(PCA、SelectKbest、ColumnTransformer……的特定结果)感兴趣,我不知道如何从管道中提取它们,我猜这是不可能的。
2) 使用keras模型时,对于单一的回归和分类模型,我不知道如何应用keras包装器来使用例如Pipeline。
关于您的代码
I
如果您对每个转换的中间输出感兴趣,您将不会使用管道。
keras模型通过包装器可以作为管道的最后一步。
谢谢 Jason
不客气。
您是我的灵感。您优雅地解释了主题,现在概念非常清晰。谢谢Jason!
大家好,我使用了这段代码进行管道设置,我遇到了这个错误,请帮帮我
pipe = Pipeline([(‘scaler’, StandardScaler()),
(‘Logestic’,LogisticRegression()),
(‘SVM’,SVC())])
错误
所有中间步骤都应该是转换器并且实现fit和transform,或者应该是字符串‘passthrough’‘LogisticRegression()’(类型)不应该。
Hasti你好…在研究这个错误时,我偶然发现了以下资源
https://stackoverflow.com/questions/48758383/all-intermediate-steps-should-be-transformers-and-implement-fit-and-transform