Scikit Learn中流水线入门指南

2025年3月3日 | 13 分钟阅读

机器学习管道是处理数据在通过特定的机器学习模型或一组模型之前和之后的所有过程的总称。它包括输入数据、特征、输出、机器学习算法、模型中的参数以及预测输出。

机器学习中管道的重要性

机器学习管道的设计,并在一定程度上,执行是企业级人工智能软件的关键部分,并直接定义其性能和成功。除了关于软件设计的说法,还有使用哪些机器学习库以及运行时环境(处理器、内存和存储)的问题。

许多现实世界中的机器学习应用依赖于各种中间步骤,因此整个管道非常庞大。后者可能需要不同的库和运行时,并且可能必须在不同的硬件配置文件上执行。这意味着在算法设计和开发以及维护过程中,应考虑库、运行时和相应的硬件配置文件的管理。设计控制可以导致在固定成本以及算法性能上的巨大差异。

使用机器学习管道的优点

  1. 模块化:在管道中,您可以将机器学习过程逻辑地、顺序地分解为易于定义的组件。这也意味着每个步骤都可以单独进行工作、改进和微调,从而使工作流管理问题更少。
  2. 可复现性:机器学习管道的另一个优点是我们可以重现实验或在新数据集上进行尝试。借助这种结构,您可以为任何管道定义一系列步骤和参数,并且每次都能获得过程的重现。如果某个步骤失败或模型的性能变差,则可以设置管道以发送警报甚至纠正问题。
  3. 效率:管道处理许多琐碎的过程,如数据清洗、数据转换和模型评估。这种效率节省了大量时间,并且还可以纠正一些错误。
  4. 可扩展性:通过管道,可以保持可扩展性,从而可以处理大型数据集或复杂的 [工作流](https://www.tpoint.in/tutorial/programming/data-science/machine-learning-workflow)。在处理大量数据和模型时,管道的组件可以独立于其他组件进行修改,因此无需从头开始重新配置新管道,这会花费太长时间。
  5. 实验:如果您想尝试一些数据预处理技术、新特征或特征组合,或者想尝试新模型,您可以通过调整管道的任何步骤来实现。这种灵活性允许以非常快的速度进行调整,同时优化解决方案。

Scikit-learn 是 [Python](https://www.tpoint.in/tutorial/python) 提供的一个库,用于创建机器学习算法,并提供了广泛的数据分析和数据挖掘工具。使用该库创建管道可提供旨在自动化机器学习项目任务的功能。Scikit-learn 中的管道指示机器学习任务中的处理步骤顺序,从数据预处理到从数据中提取特征,以解决任何类型的问题,无论是分类问题还是回归问题。机器学习中的管道不仅提供了代码的清晰性和可维护性,还提高了机器学习算法的效率和可复现性。通过将管道添加到机器学习工作流中,可以获得结构化且无错误的方法。

Scikit-learn 中的管道是一个工具,它将所有数据预处理和建模步骤组合成一个单一的、简化的单元。让我们看一下管道的核心组件。

Scikit-Learn 管道的核心组件

变压器

Transformer 是负责数据准备步骤的重要部分。Transformer 实现的函数

  • fit(x, y):使用训练数据 (x, y) 通过 transform 函数学习模式和参数。
  • transform(x):将从训练数据中学到的模式应用于转换输入数据 (x)。
  • 例如,为了保持机器学习算法的泛化性,对训练数据进行归一化和标准化,以及将类别特征编码为数字特征,都是使用 fit 和 transform 方法进行的。

Estimator

Estimator 是机器学习管道的最后一步,负责实际的机器学习任务,即分类和回归。Estimator 实现的函数。

  • fit(x, y):Estimator 使用 fit 函数,通过训练数据 X 和 y 训练模型,其中 X 是输入变量,y 是输出变量。
  • predict(X):在通过算法对训练数据进行拟合以学习数据中的模式之后,Estimator 使用在数据上训练的模型来预测未知数据 (X)。

代码可维护性的好处

  • 封装:机器学习工作流中的管道将所有预处理和建模步骤组合成一个单一的对象,使代码更清晰、更模块化,并且更易于处理和管理。
  • 减少代码重复:通过在机器学习工作流中使用管道,可以避免重复预处理步骤,并在与不同模型一起使用时避免这些重复。
  • 清晰的工作流:管道定义了数据处理的结构化序列,从而提高了代码的可读性。

可复现性

标准化工作流:由于所有步骤都分组在管道中,因此可以轻松地在新数据上复制整个机器学习工作流。

版本控制:可以通过管道和模型参数来控制模型的版本,从而确保任何人都可以使用该管道来再次生成结果。

使用 Scikit-Learning 构建管道

管道是通过将数值特征和类别特征的预处理路径分开定义来创建的。

  • 数值预处理器:数值预处理器有助于使用均值填充缺失值,然后对数据进行缩放。
  • 类别预处理器:缺失的类别用“缺失”值填充,然后应用独热编码技术对类别进行处理,将类别变量转换为数值,以便机器学习模型能够处理。

所有预处理步骤都通过 ColumnTransformer 连接在一起,ColumnTransformer 允许输入数据中的不同列被处理。这对于包含各种数据类型并需要使用不同预处理技术的 [数据集](https://www.tpoint.in/tutorial/programming/data-science/datasets) 非常有用。在执行所有转换后,使用 make_pipeline 函数构建管道,该函数不仅包含预处理步骤,还会在最后一步添加机器学习模型。此管道不仅可以高效地训练模型,还可以轻松地预测新数据,因为在将新数据输入模型进行预测时,所有预处理步骤都会自动应用到新数据上。让我们为数据创建一个管道并向管道添加模型。然后,我们将通过拟合训练数据来训练该模型,并使用此管道预测新数据。

代码

输出

A Basic Introduction to Pipelines in Scikit Learn

说明

上面的代码演示了一个用于数据预处理的机器学习管道,并且该预处理后的数据在一个 SVM 分类器上进行训练。该数据集包含数值和类别特征,并且数据中存在一些缺失值。“SimpleImputer”用于填充数值缺失值(用均值填充),类别缺失值被替换为常量“missing”。数值特征使用 StandardScaler 进行标准化,而类别特征使用 OneHotEncoder 进行编码。不同特征的预处理步骤使用 ColumnTransformer 组合。然后将预处理后的数据传递给 SVC(支持向量分类器)模型。整个管道被封装在机器学习管道中,这使得应用预处理和训练模型变得容易。model_pipeline 用于拟合、预测和评估模型。

通过在机器学习工作流中使用 make_pipeline 和 ColumnTransformer,有助于简化可维护的训练。上面的代码还通过确保预处理步骤和预测在整个过程中持续应用,使代码清晰且模块化。通过编写代码,可以使用此管道预测数据。

代码

输出

 
[1 1 0 1 1 1]   

说明

在上面的代码中,特征变量和目标变量被分割成训练集和测试集,模型管道在训练集上拟合,模型在测试集上进行测试。

特征联合

Feature unions 是 Scikit-learn 提供的一种方法,它允许将多个转换器并行应用,并在输入到 estimator 之前将输出连接起来。当数据集的不同子集需要独特的转换时使用它。FeatureUnion 的工作方式与 ColumnTransformer 非常相似,但提供了更多灵活性,允许组合多个管道。

让我们来看一个使用 FeatureUnion 的管道示例。

代码

说明

机器学习管道通过将特征提取和分类集成到单个工作流中来创建。通过 FeaturUnion 组合了两种特征提取技术:PCA(主成分分析),它将维度减少到 2 个分量;SelectKBest,它根据特征选择最重要的 2 个特征。创建的管道使用 make_pipeline 构建,该管道从 StandardScaler 开始标准化特征,然后是特征提取技术,最后应用 RandomForestClassifier,它使用 100 个决策树来实现分类。该管道有助于简化数据预处理、特征提取和模型训练技术。

代码

输出

 
Combined space has 8 features
Fitting 5 folds for each of 81 candidates, totaling 405 fits
[CV 1/5; 1/81] START classifier__max_depth=5, classifier__n_estimators=50, features__feature_select__percentile=30, features__kernel_pca__n_components=1
[CV 1/5; 1/81] END classifier__max_depth=5, classifier__n_estimators=50, features__feature_select__percentile=30, features__kernel_pca__n_components=1;, score=0.833 total time=   0.2s
[CV 2/5; 1/81] START classifier__max_depth=5, classifier__n_estimators=50, features__feature_select__percentile=30, features__kernel_pca__n_components=1
[CV 2/5; 1/81] END classifier__max_depth=5, classifier__n_estimators=50, features__feature_select__percentile=30, features__kernel_pca__n_components=1;, score=0.861 total time=   0.2s
[CV 3/5; 1/81] START classifier__max_depth=5, classifier__n_estimators=50, features__feature_select__percentile=30, features__kernel_pca__n_components=1
[CV 3/5; 1/81] END classifier__max_depth=5, classifier__n_estimators=50, features__feature_select__percentile=30, features__kernel_pca__n_components=1;, score=0.917 total time=   0.2s
[CV 4/5; 1/81] START classifier__max_depth=5, classifier__n_estimators=50, features__feature_select__percentile=30, features__kernel_pca__n_components=1

说明

在上面的代码中,通过结合降维、特征选择和模型训练,使用管道对 win 数据集执行分类。加载数据集,并通过使用 Kernel PCA 将数据减少到 2 维。应用 SelectPercentile 以基于单变量分数获得最重要的 50% 特征。使用 FeatureUnion 组合了这两种技术提取的特征。使用这些特征创建的管道与 RandomForestClassifier 结合。GridSearchCV 用于调整超参数,并转换特征和分类器。根据交叉验证性能选择最佳模型。

常见问题和修复技术

数据维度不一致 症状:关于数据形状或维度不准确,以及变换的存在。

解决方案:检查所有转换器是否以正确的格式处理数据。

如果需要调整数据形状,则使用 FunctionTransformer。

问题:预处理步骤不一致

  • 症状:模型性能的停滞或衰减,会周期性或在任何给定时间发生。
  • 解决方案:检查管道中的所有预处理操作是否正确。数据的预处理必须一致,才能获得更好的模型性能。

问题:参数设置不正确

  • 症状:模型要么不收敛,要么性能不理想。
  • 解决方案:确保验证管道中的参数名称和值,特别是如果它们在 GridSearchCV 或 RandomizedSearchCV 中设置。确保为每个步骤设置的参数网格正确。

调试技巧

  • 增量测试:单独分析管道的每个部分,然后一次性组合。这样更容易确定错误发生的确切位置。
  • 详细输出:在管道构建和模型训练中使用 verbose 参数获取日志。这可以提示管道在每个实例中正在做什么。
  • 管道检查:scikit-learn 提供了许多指标,您可以使用它们,包括成对指标,如准确率、PrecisionRecallDisplay、ClassificationReport,top-k 指标,如精确率、召回率和 F1 分数等。您可以使用管道的 named_steps 属性来检查单个步骤及其参数。这对于确保每个步骤都按计划设置非常有用。

性能优化策略

缓存 Transformer

  • 目的:为网格搜索、交叉验证和其他一般实验问题节省时间。
  • 实现:使用管道的 memory 参数缓存 Transformer。

并行化网格搜索

  • 目的:通过同时执行不同参数组合来加速网格搜索和随机搜索等交叉验证策略。
  • 实现:在 GridSearchCV 或 RandomizedSearchCV 中使用的 n_jobs 参数用于确定并行运行的作业数。n_jobs=-1 可用于使用所有可用的 CPU 核心,而 n_jobs=1 只使用一个核心。

自定义组件是使用基本管道或现成管道元素构建的附加管道。

创建自定义 Transformer

要创建自定义 Transformer,您需要定义一个实现至少两个方法的类。一些最常用的方法包括 fit() 和 transform() 方法。选择这些方法的原因之一是,为了方便并与 Scikit-learn 的管道机制兼容,继承自 BaseEstimator 和 TransformerMixin 也是一个好习惯。这使得它提供了像 get_params()(我们检索参数的地方)、set_params()(我们设置参数的地方)以及 fit_transform() 方法这样的实用方法的默认实现。

fit() 方法用于根据输入数据设置 Transformer,并且在需要时(例如,用于归一化的均值)还可以学习参数。它通常返回自身。

transform() 方法使用给定的转换逻辑转换输入数据,并返回转换后的数据集。如果您继承自 TransformerMixin,您将免费获得 fit_transform(),它结合了 fit() 和 transform()。

示例:从头开始构建 Scaler

代码

输出

 
Original Data:
 [[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]
Scaled Data:
 [[0.         0.         0.        ]
 [0.33333333 0.33333333 0.33333333]
 [0.66666667 0.66666667 0.66666667]
 [1.         1.         1.        ]]   

说明

在上面的代码中,通过创建一个 RangeScaler 类实现了自定义缩放器,该类将数据缩放到 0 到 1 的特定范围。该类继承自 BaseEstimator TransformerMixin,因此它可以集成到 scikit-learn 管道中。fit 方法计算每个特征的最小值和范围并存储它。如果 x 小于 data-min 或大于 data-max,则使用以下公式 (x-min)/(max-min) 进行缩放,然后使用指定的 scale_range 将其缩放到目标范围。之后,它在样本数据 X 上使用缩放器,通过拟合数据来拟合缩放器,然后转换数据,之后打印原始数据和缩放后的数据。