为什么 sklearn Pipeline 调用 transform() 的次数比 fit() 多很多?
Why does sklearn Pipeline call transform() so many more times than fit()?
经过大量阅读和检查 pipeline.fit() 在不同 verbose
参数设置下的操作,我仍然很困惑为什么我的管道访问某个步骤的 transform
方法很多次。
下面是一个简单的例子 pipeline
,fit
和 GridSearchCV
,使用 3 折交叉验证,但参数网格只有一组超参数。所以我预计流水线会运行 3 次。正如预期的那样,step1
和 step2
都被调用了 3 次 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)
输出:
Fitting step 1
Transforming step 1
Fitting step 2
Transforming step 2
Transforming step 1
Transforming step 2
Transforming step 1
Transforming step 2
Fitting step 1
Transforming step 1
Fitting step 2
Transforming step 2
Transforming step 1
Transforming step 2
Transforming step 1
Transforming step 2
Fitting step 1
Transforming step 1
Fitting step 2
Transforming step 2
Transforming step 1
Transforming step 2
Transforming step 1
Transforming step 2
因为您已将 GridSearchCV
与 cv = KFold(3)
一起使用,这将对您的模型进行交叉验证。事情是这样的:
- 它将数据分成两部分:训练和测试。
- 对于train,它会拟合和转换pipeline的每个部分(不包括最后一个,它是分类器)。这就是为什么您会看到
fit step1, transform step1, fit step2, transform step2
.
- 它将适合分类器上的转换数据(它不会打印在您的输出中。
已编辑 现在是计分部分。在这里,我们不想再次重新安装零件。我们将使用在之前的拟合中学到的信息。所以管道的每个部分只会调用 transform()。这就是 Transforming step 1, Transforming step 2
.
的原因
它显示了两次,因为在 GridSearchCV 中,默认行为是计算训练和测试数据的分数。此行为由 return_train_score
控制。您可以设置 return_train_score=False
并且只会看到它们一次。
此转换后的测试数据将用于预测分类器的输出。 (同样,没有适合测试,只有预测或转换)。
- 预测值将用于与实际值进行比较,从而为模型评分。
- 步骤 1-6 将重复 3 次
(KFold(3))
。
现在看看你的参数:
param_grid = {'step1__multiplier': [2], #,3],
'step2__meaningless_param': ['hello'] #, 'howdy', 'goodbye']
}
展开时,变成单一组合即:
组合1: 'step1__multiplier'=2, 'step2__meaningless_param' = 'hello'
如果您提供了更多选项,您已经评论过更多选项,则可能会有更多组合,例如:
组合1: 'step1__multiplier'=2, 'step2__meaningless_param' = 'hello'
组合2: 'step1__multiplier'=3, 'step2__meaningless_param' = 'hello'
组合3: 'step1__multiplier'=2, 'step2__meaningless_param' = 'howdy'
等等..
将针对每种可能的组合重复步骤 1-7。
- 将选择在交叉验证的测试折叠上给出最高平均分的组合,以最终用完整的数据拟合模型(不分为训练和测试)。
但是你保留了refit=False
。所以该模型将不会再次拟合。否则你会看到
的另一个输出
拟合步骤一
改造步骤一
装配步骤 2
转换步骤 2
希望这能解决这个问题。欢迎询问更多信息。
经过大量阅读和检查 pipeline.fit() 在不同 verbose
参数设置下的操作,我仍然很困惑为什么我的管道访问某个步骤的 transform
方法很多次。
下面是一个简单的例子 pipeline
,fit
和 GridSearchCV
,使用 3 折交叉验证,但参数网格只有一组超参数。所以我预计流水线会运行 3 次。正如预期的那样,step1
和 step2
都被调用了 3 次 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)
输出:
Fitting step 1
Transforming step 1
Fitting step 2
Transforming step 2
Transforming step 1
Transforming step 2
Transforming step 1
Transforming step 2
Fitting step 1
Transforming step 1
Fitting step 2
Transforming step 2
Transforming step 1
Transforming step 2
Transforming step 1
Transforming step 2
Fitting step 1
Transforming step 1
Fitting step 2
Transforming step 2
Transforming step 1
Transforming step 2
Transforming step 1
Transforming step 2
因为您已将 GridSearchCV
与 cv = KFold(3)
一起使用,这将对您的模型进行交叉验证。事情是这样的:
- 它将数据分成两部分:训练和测试。
- 对于train,它会拟合和转换pipeline的每个部分(不包括最后一个,它是分类器)。这就是为什么您会看到
fit step1, transform step1, fit step2, transform step2
. - 它将适合分类器上的转换数据(它不会打印在您的输出中。
已编辑 现在是计分部分。在这里,我们不想再次重新安装零件。我们将使用在之前的拟合中学到的信息。所以管道的每个部分只会调用 transform()。这就是
的原因Transforming step 1, Transforming step 2
.它显示了两次,因为在 GridSearchCV 中,默认行为是计算训练和测试数据的分数。此行为由
return_train_score
控制。您可以设置return_train_score=False
并且只会看到它们一次。此转换后的测试数据将用于预测分类器的输出。 (同样,没有适合测试,只有预测或转换)。
- 预测值将用于与实际值进行比较,从而为模型评分。
- 步骤 1-6 将重复 3 次
(KFold(3))
。 现在看看你的参数:
param_grid = {'step1__multiplier': [2], #,3], 'step2__meaningless_param': ['hello'] #, 'howdy', 'goodbye'] }
展开时,变成单一组合即:
组合1: 'step1__multiplier'=2, 'step2__meaningless_param' = 'hello'
如果您提供了更多选项,您已经评论过更多选项,则可能会有更多组合,例如:
组合1: 'step1__multiplier'=2, 'step2__meaningless_param' = 'hello'
组合2: 'step1__multiplier'=3, 'step2__meaningless_param' = 'hello'
组合3: 'step1__multiplier'=2, 'step2__meaningless_param' = 'howdy'
等等..
将针对每种可能的组合重复步骤 1-7。
- 将选择在交叉验证的测试折叠上给出最高平均分的组合,以最终用完整的数据拟合模型(不分为训练和测试)。
但是你保留了
的另一个输出refit=False
。所以该模型将不会再次拟合。否则你会看到拟合步骤一 改造步骤一 装配步骤 2 转换步骤 2
希望这能解决这个问题。欢迎询问更多信息。