为什么sklearn Pipeline调用transform()比fit()多多次?

时间:2017-11-01 20:15:47

标签: python machine-learning scikit-learn pipeline

经过大量阅读并检查不同verbose参数设置下的pipeline.fit()操作后,我仍然困惑为什么我的管道访问某个步骤{{1方法这么多次。

以下是一个简单的示例transformpipelinefit,使用3倍交叉验证,但是只有一组超行程的param-grid。所以我预计会有三次贯穿整个管道。正如预期的那样,GridSearchCVstep1都有step2被调用了三次,但每个步骤都fit被调用了几次。为什么是这样?下面的最小代码示例和日志输出。

transform

输出:

# library imports
import pandas as pd
from sklearn import datasets
from sklearn.model_selection import KFold
from sklearn.linear_model import LogisticRegression
from sklearn.base import TransformerMixin, BaseEstimator
from sklearn.pipeline import Pipeline

# Load toy data
iris = datasets.load_iris()
X = pd.DataFrame(iris.data, columns = iris.feature_names)
y = pd.Series(iris.target, name='y')

# Define a couple trivial pipeline steps
class mult_everything_by(TransformerMixin, BaseEstimator):

    def __init__(self, multiplier=2):
        self.multiplier = multiplier

    def fit(self, X, y=None):
        print "Fitting step 1"
        return self

    def transform(self, X, y=None):
        print "Transforming step 1"
        return X* self.multiplier

class do_nothing(TransformerMixin, BaseEstimator):

    def __init__(self, meaningless_param = 'hello'):
        self.meaningless_param=meaningless_param


    def fit(self, X, y=None):
        print "Fitting step 2"
        return self

    def transform(self, X, y=None):
        print "Transforming step 2"
        return X

# Define the steps in our Pipeline
pipeline_steps = [('step1', mult_everything_by()),
                  ('step2', do_nothing()), 
                  ('classifier', LogisticRegression()),
                  ]

pipeline = Pipeline(pipeline_steps)

# To keep this example super minimal, this param grid only has one set
# of hyperparams, so we are only fitting one type of model
param_grid = {'step1__multiplier': [2],   #,3],
              'step2__meaningless_param': ['hello']   #, 'howdy', 'goodbye']
              }

# Define model-search process/object
# (fit one model, 3-fits due to 3-fold cross-validation)
cv_model_search = GridSearchCV(pipeline, 
                               param_grid, 
                               cv = KFold(3),
                               refit=False, 
                               verbose = 0) 

# Fit all (1) models defined in our model-search object
cv_model_search.fit(X,y)

1 个答案:

答案 0 :(得分:3)

因为您已将GridSearchCVcv = KFold(3)一起使用,它将对您的模型进行交叉验证。这里发生了什么:

  1. 它会将数据分成两部分:训练和测试。
  2. 对于火车,它将适合并转换管道的每个部分(不包括最后一个,即分类器)。这就是你看到fit step1, transform step1, fit step2, transform step2
  3. 的原因
  4. 它会将转换后的数据放在分类器上(不会在输出中打印出来。
  5. 已编辑现在是评分部分。在这里,我们不想再次重新装配零件。我们将使用之前拟合期间学到的信息。所以管道的每个部分都只调用transform()。这就是Transforming step 1, Transforming step 2的原因。

    它显示两次,因为在GridSearchCV中,默认行为是计算训练和测试数据的得分。此行为由return_train_score进行调整。您可以设置return_train_score=False,只会看一次。

  6. 此转换后的测试数据将用于预测分类器的输出。 (同样,不适合测试,只预测或转换)。

  7. 预测值将用于与实际值进行比较以对模型进行评分。
  8. 步骤1-6将重复3次(KFold(3))
  9. 现在看看你的参数:

    param_grid = {' step1__multiplier':[2],#,3],               ' step2__meaningless_param':['你好']#,'你好','再见']               }

    扩展时,它只是单一的组合,即:

    组合1 :' step1__multiplier' = 2,' step2__meaningless_param' ='你好'

    如果您提供了更多选项,您已评论过更多选项,例如:

    组合1 :' step1__multiplier' = 2,' step2__meaningless_param' ='你好'

    组合2 :' step1__multiplier' = 3,' step2__meaningless_param' ='你好'

    组合3 :' step1__multiplier' = 2,' step2__meaningless_param' ='你好'

    依旧......

  10. 对于每种可能的组合,将重复步骤1-7。

  11. 将选择在交叉验证的测试折叠上给出最高平均得分的组合,以最终使模型具有完整数据(不划分为列车和测试)。
  12. 但你保留了refit=False。所以模型不会再适合。否则你会看到另外一个

    的输出

    拟合步骤1 转变步骤1 拟合步骤2 转变第2步

  13. 希望这可以解决这个问题。随意询问更多信息。