sklearn.pipeline.Pipeline 到底是什么?

What is exactly sklearn.pipeline.Pipeline?

我不明白 sklearn.pipeline.Pipeline 是如何工作的。

doc中有一些解释。例如,它们是什么意思:

Pipeline of transforms with a final estimator.

为了让我的问题更清楚,steps 是什么?它们是如何工作的?

编辑

感谢您的回答,我可以使我的问题更清楚:

当我调用管道并作为步骤传递两个转换器和一个估算器时,例如:

pipln = Pipeline([("trsfm1",transformer_1),
                  ("trsfm2",transformer_2),
                  ("estmtr",estimator)])

当我调用这个时会发生什么?

pipln.fit()
OR
pipln.fit_transform()

我无法弄清楚估算器如何成为转换器以及如何安装转换器。

我认为 M0rkHaV 的想法是正确的。 Scikit-learn 的管道 class 是一种有用的工具,可将多个不同的转换器与一个估算器一起封装到一个对象中,这样您只需调用一次重要方法(fit()predict() 等).让我们分解两个主要组成部分:

  1. 变形金刚 是 class 同时实现 fit()transform() 的实体。您可能熟悉一些 sklearn 预处理工具,例如 TfidfVectorizerBinarizer。如果您查看这些预处理工具的文档,您会发现它们实现了这两种方法。我觉得很酷的是一些估计器也可以用作转换步骤,例如LinearSVC!

  2. Estimators 是实现了 fit()predict() 的 classes。您会发现许多 class 化器和回归模型都实现了这两种方法,因此您可以轻松地测试许多不同的模型。可以使用另一个转换器作为最终估计器(即,它不一定实现 predict(),但肯定实现 fit())。这意味着您将无法调用 predict().

关于您的编辑:让我们来看一个基于文本的示例。使用 LabelBinarizer,我们希望将标签列表转换为二进制值列表。

bin = LabelBinarizer()  #first we initialize

vec = ['cat', 'dog', 'dog', 'dog'] #we have our label list we want binarized

现在,当二值化器适用于某些数据时,它将有一个名为 classes_ 的结构,其中包含转换器 'knows' 所涉及的唯一 classes。如果不调用 fit(),二值化器不知道数据是什么样子,所以调用 transform() 没有任何意义。如果您在尝试拟合数据之前打印出 classes 的列表,就会出现这种情况。

print bin.classes_  

尝试此操作时出现以下错误:

AttributeError: 'LabelBinarizer' object has no attribute 'classes_'

但是当您将二值化器放入 vec 列表时:

bin.fit(vec)

再试一次

print bin.classes_

我得到以下信息:

['cat' 'dog']


print bin.transform(vec)

现在,在 vec 对象上调用转换后,我们得到以下内容:

[[0]
 [1]
 [1]
 [1]]

至于将估计器用作变换器,让我们使用 DecisionTree classifier 作为特征提取器的示例。决策树之所以伟大有很多原因,但就我们的目的而言,重要的是它们能够对 发现对预测有用的特征进行排名。当您在决策树上调用 transform() 时,它会获取您的输入数据并找到 认为最重要的特征。因此,您可以考虑将数据矩阵(n 行 x m 列)转换为更小的矩阵(n 行 x k 列),其中 k 列是决策树找到的 k 个最重要的特征。

scikit-learn 中的 Transformer - 一些 class 具有拟合和变换方法,或 fit_transform 方法。

Predictor - 一些 class 具有拟合和预测方法,或 fit_predict 方法。

Pipeline只是一个抽象的概念,不是现有的一些ml算法。通常在 ML 任务中,您需要在应用最终估计器之前对原始数据集执行一系列不同的转换(查找特征集、生成新特征、select 仅一些好的特征)。

Here 是 Pipeline 用法的一个很好的例子。 Pipeline 为您提供了用于所有 3 个转换步骤和结果估算器的单一界面。它在里面封装了transformers和predictors,现在你可以这样做:

    vect = CountVectorizer()
    tfidf = TfidfTransformer()
    clf = SGDClassifier()

    vX = vect.fit_transform(Xtrain)
    tfidfX = tfidf.fit_transform(vX)
    predicted = clf.fit_predict(tfidfX)

    # Now evaluate all steps on test set
    vX = vect.fit_transform(Xtest)
    tfidfX = tfidf.fit_transform(vX)
    predicted = clf.fit_predict(tfidfX)

只有:

pipeline = Pipeline([
    ('vect', CountVectorizer()),
    ('tfidf', TfidfTransformer()),
    ('clf', SGDClassifier()),
])
predicted = pipeline.fit(Xtrain).predict(Xtrain)
# Now evaluate all steps on test set
predicted = pipeline.predict(Xtest)

使用管道,您可以轻松地对该元估计器的每个步骤的参数集执行网格搜索。如上面 link 中所述。除最后一步外的所有步骤都必须是变换,最后一步可以是变换器或预测器。 编辑答案: 当您调用 pipln.fit() - 管道内的每个变压器都将安装在前一个变压器的输出上(第一个变压器是在原始数据集上学习的)。 Last estimator 可能是 transformer 或 predictor,只有当你的 last estimator 是 transformer(实现 fit_transform,或分别实现 transform 和 fit 方法)时,你才可以在管道上调用 fit_transform(),你可以调用 fit_predict() 或 predict() 仅当您的最后一个估算器是预测器时才在管道上使用。所以你不能在管道上调用 fit_transform 或转换,最后一步是预测器。

ML algorithms typically process tabular data. You may want to do preprocessing and post-processing of this data before and after your ML algorithm. A pipeline is a way to chain those data processing steps.

What are ML pipelines and how do they work?

管道是转换数据的一系列步骤。它来自旧的“管道和过滤器”设计模式(例如,您可以想到带有管道“|”或重定向运算符“>”的 unix bash 命令)。但是,管道是代码中的对象。因此,对于每个过滤器(a.k.a。每个流水线步骤),您可能有一个 class,然后另一个 class 将这些步骤组合到最终流水线中。一些流水线可能串联或并联其他流水线,具有多个输入或输出等。我们喜欢将 Pipelining Machine Learning 视为:

  • Pipe and filters。流水线的步骤处理数据,它们管理可以从数据中学习的内部状态。
  • Composites。管道可以嵌套:例如,整个管道可以被视为另一个管道中的单个管道步骤。流水线步骤不一定是流水线,但根据定义,流水线本身至少是流水线步骤。
  • Directed Acyclic Graphs (DAG)。流水线步骤的输出可能会发送到许多其他步骤,然后可以重新组合结果输出,等等。旁注:尽管管道是非循环的,但它们可以一个接一个地处理多个项目,如果它们的状态发生变化(例如:每次使用 fit_transform 方法),那么它们可以被视为随时间循环展开,保持它们的状态状态(像 RNN 一样思考)。这是一种有趣的方式,可以在将在线学习投入生产并在更多数据上对其进行培训时查看进行在线学习的管道。

Scikit-Learn 管道的方法

流水线(或流水线中的步骤)必须有这两种方法:

  • fit”在数据上学习并获取状态(例如:神经网络的神经权重就是这样的状态)
  • transform”(或“预测”)实际处理数据并生成预测。

也可以调用此方法来链接两者:

  • fit_transform”来拟合然后转换数据,但是在一次传递中,当两种方法必须一个接一个地直接完成时,这允许潜在的代码优化。

Problems of the sklearn.pipeline.Pipeline class

Scikit-Learn’s “pipe and filter” design pattern is simply beautiful. But how to use it for Deep Learning, AutoML, and complex production-level pipelines?

Scikit-Learn 于 2007 年首次发布,当时 pre deep learning era。然而,它是最著名和采用最多的机器学习库之一,并且还在不断增长。最重要的是,它使用管道和过滤器设计模式作为软件架构风格——这就是 Scikit-Learn 如此出色的原因,此外,它还提供了可供使用的算法。但是,它在执行以下操作时存在大量问题,我们应该可以在 2020 年完成这些操作:

  • 自动机器学习 (AutoML),
  • 深度学习管道,
  • 更复杂的机器学习管道。

我们找到的解决 Scikit-Learn 问题的方法

当然,Scikit-Learn 非常方便且构建良好。但是,它需要刷新。以下是我们使用 Neuraxle 的解决方案,使 Scikit-Learn 在现代计算项目中变得新鲜且可用!

通过 Neuraxle

提供的其他管道方法和功能

注意:如果管道的某个步骤不需要 fit 或 transform 方法之一,它可以继承自 NonFittableMixin or NonTransformableMixin 以提供这些方法之一的默认实现,以不执行任何操作.

作为初学者,管道或其步骤也可以选择性地定义这些方法:

  • setup” 将在其每个步骤中调用“setup”方法。例如,如果一个步骤包含 TensorFlow、PyTorch 或 Keras 神经网络,则这些步骤可以创建它们的神经图并在拟合之前在“setup”方法中将它们注册到 GPU。出于多种原因,不鼓励直接在步骤的构造函数中创建图形,例如,如果在自动机器学习算法中使用不同的超参数多次复制步骤 运行,为您搜索最佳超参数.
  • teardown”,与“setup”方法相反:清除资源

默认提供以下方法以允许管理超参数:

  • get_hyperparams”将为您 return 超参数字典。如果您的管道包含更多管道(嵌套管道),则超参数的键使用双下划线“__”分隔符链接。
  • set_hyperparams”将允许您以与获取它们时相同的格式设置新的超参数。
  • get_hyperparams_space”可以得到超参数的space,定义了超参数就不为空。因此,此处与“get_hyperparams”的唯一区别是您将获得统计分布值而不是精确值。例如,层数的一个超参数可以是 RandInt(1, 3),这意味着 1 到 3 层。你可以在这个 dict 上调用 .rvs() 来随机选择一个值并将其发送到“set_hyperparams”以尝试对其进行训练。
  • set_hyperparams_space”可用于设置新的space,使用与“get_hyperparams_space”相同的超参数分布classes .

有关我们建议的解决方案的更多信息,请阅读带有上面链接的大列表中的条目。

    from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.preprocessing import StandardScaler
from sklearn import metrics
import pandas as pd

class TextTransformer(BaseEstimator, TransformerMixin):
    """
    Преобразование текстовых признаков
    """
    def __init__(self, key):
        self.key = key

    def fit(self, X, y=None, *parg, **kwarg):
        return self

    def transform(self, X):
        return X[self.key]
    

class NumberTransformer(BaseEstimator, TransformerMixin):
    """
    Преобразование числовых признаков
    """
    def __init__(self, key):
        self.key = key

    def fit(self, X, y=None):
        return self

    def transform(self, X):
        return X[[self.key]]



def fit_predict(model, X_train, X_test, y_train, y_test):
    vec_tdidf = TfidfVectorizer(ngram_range=(2,2), analyzer='word', norm='l2')
    
    text = Pipeline([
                    ('transformer', TextTransformer(key='clear_messages')),
                    ('vectorizer', vec_tdidf)
                    ])
    word_numeric = Pipeline([
                    ('transformer', NumberTransformer(key='word_count')),
                    ('scalar', StandardScaler())
                    ])
    word_class = Pipeline([
                    ('transformer', NumberTransformer(key='preds')),
                    ('scalar', StandardScaler())
                    ])
    # Объединение всех признаков
    features = FeatureUnion([('Text_Feature', text),
                             ('Num1_Feature', word_numeric),
                             ('Num2_Feature', word_class)
                            ])
    
    # Классификатор
    clf = model
    
    # Объединение классификатора и признаков
    pipe = Pipeline([('features', features),
                     ('clf',clf)
                     ])
    
    # Обучение модели
    pipe_fit=pipe.fit(X_train, y_train)
    
    # Предсказание данных
    preds = pipe_fit.predict(X_test)
    
    return preds, pipe_fit