sklearn.pipeline.Pipeline是什么?

149
我不太明白sklearn.pipeline.Pipeline的工作原理。
文档中有一些解释。例如,他们所说的“带有最终估算器的变换管道”是什么意思?
为了更清楚地表达我的问题,什么是steps?它们是如何工作的? 编辑 感谢答案,我可以进一步澄清我的问题:
当我调用pipeline并将两个转换器和一个评估器作为steps传递时,例如:
pipln = Pipeline([("trsfm1",transformer_1),
                  ("trsfm2",transformer_2),
                  ("estmtr",estimator)])

我打电话时会发生什么?

pipln.fit()
OR
pipln.fit_transform()

我不明白估计器如何成为变压器,以及变压器如何适应。


4
据我所了解,管道可以帮助您自动化学习过程中的多个步骤,如模型的训练和测试、特征选择等。因此,如果您想将回归模型与分类器结合使用,那么您需要进行回归模型的训练,然后再进行分类器的训练。编辑:添加细节。 - M0rkHaV
1
我发现这篇文章很有帮助:http://queirozf.com/entries/scikit-learn-pipeline-examples - randomSampling
4个回答

231

Transformer 是scikit-learn中的一些类,具有fit和transform方法或fit_transform方法。

Predictor 是一些具有fit和predict方法或fit_predict方法的类。

Pipeline 只是一个抽象的概念,它不是某种现有的机器学习算法。在许多机器学习任务中,在应用最终评估器之前,需要对原始数据集执行不同的转换序列(找到一组特征、生成新特征、选择好的特征)。

这里 提供了Pipeline使用的一个很好的例子。Pipeline为所有三个转换步骤和结果评估器提供单一的接口。它封装了变换器和预测器,并且现在您可以像这样进行操作:

    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)
使用管道,您可以轻松地为此元估计器的每个步骤执行一组参数的网格搜索。如上面的链接所述,除了最后一步之外的所有步骤都必须是变换器,而最后一步可以是变换器或预测器。 编辑回答: 当您调用pipeline.fit()时,管道中的每个变换器都将在前一个变换器的输出上进行拟合(第一个变换器在原始数据集上学习)。最后一个评估器可以是变换器或预测器,仅当您的最后一个评估器是实现fit_transform或transform和fit方法的变换器时,您才能在管道上调用fit_transform()方法。如果您的最后一个评估器是预测器,则只能在管道上调用fit_predict()或predict()方法。因此,如果管道的最后一步是预测器,则不能调用fit_transform或transform方法。

2
“predicted = pipeline.fit(Xtrain).predict(Xtrain)” 的意思是什么? - farhawa
@farhawa,在训练集上预测类别。 - Ibraim Ganiev
7
为什么这个没有更多的投票?它应该成为一篇博客文章。 - R Claven
1
@iamgin,大多数scikit-learn转换器的接口不允许选择我们想要转换的所需列。但是,您可以编写自己的“项目选择器”,以帮助您仅将所需列提供给转换器。这里有一个使用ItemSelector和FeatureUnion的好例子http://scikit-learn.org/stable/auto_examples/hetero_feature_union.html#sphx-glr-auto-examples-hetero-feature-union-py - Ibraim Ganiev
3
在第一个例子中,您不想再次使用测试集进行拟合吗? 应该只调用transform而不是fit_transform吧?类似地,pipeline.predict内部是否调用fit_transform或仅调用transform?它能被控制吗? - Steven
显示剩余5条评论

26

我认为M0rkHaV的想法是正确的。Scikit-learn的Pipeline类是一个有用的工具,可以将多个不同的转换器和估计器封装到一个对象中,以便您只需调用重要的方法一次(fit()predict()等)。让我们分解一下这两个主要组件:

  1. 转换器是实现了fit()transform()的类。您可能熟悉一些sklearn预处理工具,如TfidfVectorizerBinarizer。如果您查看这些预处理工具的文档,您会发现它们都实现了这两种方法。我认为非常酷的是,一些估计器也可以用作转换步骤,例如LinearSVC

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

至于您的编辑: 让我们通过一个基于文本的示例来说明。使用LabelBinarizer,我们想将标签列表转换为二进制值列表。

bin = LabelBinarizer()  #first we initialize

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

现在,当二值化处理器适用于一些数据时,它将具有一个名为classes_的结构,其中包含变换器“了解”的唯一类。如果没有调用fit(),则二值化处理器不知道数据的样子,因此调用transform()是没有意义的。如果您在尝试适配数据之前打印出类列表,这也是正确的。

print bin.classes_  

当我尝试这样做时,出现以下错误:

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

但是,当您在vec列表上适配二值化器时:

bin.fit(vec)

请重试

print bin.classes_

我得到了以下内容:

['cat' 'dog']


print bin.transform(vec)

现在,在vec对象上调用transform后,我们得到以下结果:

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

关于估算器被用作转换器,让我们以DecisionTree分类器作为特征提取器的例子。决策树有很多优点,但对于我们的目的来说,重要的是它们能够对预测有用的特征进行排序。当您在决策树上调用transform()时,它会采用输入数据并找到决策树认为最重要的特征。因此,您可以将其视为将您的数据矩阵(n行m列)转换为较小的矩阵(n行k列),其中k列是决策树找到的k个最重要的特征。


在 Transformers 中,fit()transform() 有什么区别?估计器如何用作转换器? - farhawa
2
fit()是您调用的方法,用于拟合或“训练”您的转换器,就像您会对分类器或回归模型进行操作一样。至于transform(),那是您调用的方法,用于将输入数据实际转换为输出数据。例如,在拟合后调用Binarizer.transform([8,2,2])可能会导致[[1,0],[0,1],[0,1]]。至于使用估计器作为转换器,我将在我的答案中编辑一个简短的示例。 - rabbit

18
ML算法通常处理表格数据。在运行ML算法之前和之后,您可能需要对这些数据进行预处理和后处理。管道是将这些数据处理步骤链接在一起的一种方式。 什么是ML管道,它们如何工作? 管道是一系列转换数据的步骤。它来自于旧的“管道和过滤器”设计模式(例如,您可以考虑带有管道“|”或重定向运算符“>”的Unix Bash命令)。但是,管道是代码中的对象。因此,您可以为每个过滤器(也称为每个管道步骤)拥有一个类,然后再有另一个类将这些步骤组合成最终的管道。一些管道可能会串联或并联其他管道,具有多个输入或输出等。我们喜欢将机器学习的管道化视为:
- 管道和过滤器。管道的步骤处理数据,并管理其内部状态,该状态可以从数据中学习。 - 组合体。管道可以嵌套:例如,整个管道可以被视为另一个管道中的单个管道步骤。管道步骤不一定是管道,但是管道本身至少是按定义的管道步骤。 - 有向无环图(DAG)。管道步骤的输出可以发送到许多其他步骤,然后将生成的输出重新组合等。顺便说一句:尽管管道是无环的,但它们可以逐个处理多个项目,并且如果它们的状态更改(例如:每次使用fit_transform方法),则它们可以被视为通过时间循环展开,保持它们的状态(类似于RNN)。这是在生产中将管道放入在线学习时查看管道的有趣方式,以及在更多数据上对其进行培训。
Scikit-Learn管道(或管道中的步骤)必须具有这两种方法
  • fit”用于学习数据并获取状态(例如:神经网络的神经权重就是这种状态)
  • transform”(或“predict”)用于实际处理数据并生成预测。

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

  • fit_transform”用于拟合和转换数据,但在一次操作中完成,这样可以在必须直接连续执行两种方法时进行潜在的代码优化。

sklearn.pipeline.Pipeline类的问题

Scikit-Learn的“管道和过滤器”设计模式非常优美。但如何将其用于深度学习、AutoML和复杂的生产级管道?

Scikit-Learn于2007年首次发布,当时是一个深度学习之前的时代。然而,它是最知名和广泛采用的机器学习库之一,并且仍在不断发展。最重要的是,它使用管道和过滤器设计模式作为软件架构风格——这是使Scikit-Learn如此出色的原因之一,再加上它提供了可立即使用的算法。但是,当涉及以下内容时,它存在巨大问题,而我们应该已经能够在2020年做到这一点:

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

我们发现的这些Scikit-Learn问题的解决方案

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

Neuraxle提供的额外管道方法和功能

注意:如果管道的步骤不需要拥有fit或transform方法之一,它可以继承NonFittableMixinNonTransformableMixin,以便提供默认实现来什么也不做。

作为起点,管道或其步骤也可以可选地定义这些方法

  • "setup",它将在每个步骤上调用"setup"方法。例如,如果一个步骤包含TensorFlow、PyTorch或Keras神经网络,则可以在"setup"方法中创建它们的神经图并将其注册到GPU中,然后进行拟合。不建议直接在步骤的构造函数中创建图形,原因有几个,比如如果步骤在自动机器学习算法中被复制并多次运行以寻找最佳超参数。
  • "teardown",它是"setup"方法的相反操作:清除资源。

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

  • get_hyperparams”将返回一个超参数字典。如果您的管道包含更多的管道(嵌套管道),则超参数键与双下划线“__”分隔符链接。
  • set_hyperparams”将允许您以相同格式设置新的超参数。
  • get_hyperparams_space”允许您获取超参数空间,如果您定义了超参数,则不会为空。因此,这里与“get_hyperparams”的唯一区别在于,您将得到统计分布作为值,而不是精确值。例如,一个关于层数的超参数可能是RandInt(1, 3),表示1到3层。您可以在此字典上调用.rvs()随机选择一个值,并将其发送到“set_hyperparams”中尝试进行训练。
  • set_hyperparams_space”可用于使用与“get_hyperparams_space”中相同的超参数分布类设置新空间。

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


0
    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

欢迎来到 Stack Overflow。当代码配合解释时,它会更有帮助。Stack Overflow 的目的是为了学习,而不是提供盲目复制粘贴的片段。请编辑您的问题并解释它如何回答特定的问题。请参见[答案]。 - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接