将 sklearn 的 GridSearchCV 与管道一起使用,只进行一次预处理
Use sklearn's GridSearchCV with a pipeline, preprocessing just once
我正在使用 scickit-learn 来调整模型超参数。我正在使用管道将预处理与估算器链接起来。我的问题的简单版本如下所示:
import numpy as np
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
grid = GridSearchCV(make_pipeline(StandardScaler(), LogisticRegression()),
param_grid={'logisticregression__C': [0.1, 10.]},
cv=2,
refit=False)
_ = grid.fit(X=np.random.rand(10, 3),
y=np.random.randint(2, size=(10,)))
在我的例子中,预处理(玩具示例中的 StandardScale() 是什么)非常耗时,我没有调整它的任何参数。
因此,当我执行示例时,StandardScaler 被执行了 12 次。 2 fit/predict * 2 个简历 * 3 个参数。但是每次为参数 C 的不同值执行 StandardScaler 时,它 returns 相同的输出,所以它会更有效率,计算一次,然后只 运行 估计器部分管道。
我可以手动拆分预处理(未调整超参数)和估算器之间的管道。但是要对数据进行预处理,我应该只提供训练集。所以,我将不得不手动实现拆分,根本不使用 GridSearchCV。
在使用 GridSearchCV 时是否有 simple/standard 方法来避免重复预处理?
更新:
理想情况下,不应使用以下答案,因为它会导致评论中讨论的数据泄漏。在此答案中,GridSearchCV
将调整已由 StandardScaler
预处理的数据的超参数,这是不正确的。在大多数情况下这应该无关紧要,但对缩放过于敏感的算法会给出错误的结果。
本质上,GridSearchCV 也是一个估算器,实现了管道使用的 fit() 和 predict() 方法。
所以代替:
grid = GridSearchCV(make_pipeline(StandardScaler(), LogisticRegression()),
param_grid={'logisticregression__C': [0.1, 10.]},
cv=2,
refit=False)
这样做:
clf = make_pipeline(StandardScaler(),
GridSearchCV(LogisticRegression(),
param_grid={'logisticregression__C': [0.1, 10.]},
cv=2,
refit=True))
clf.fit()
clf.predict()
它会做的是,只调用 StandardScalar() 一次,一次调用 clf.fit()
而不是你描述的多次调用。
编辑:
当在管道内使用 GridSearchCV 时,将改装更改为 True
。作为 mentioned in documentation:
refit : boolean, default=True
Refit the best estimator with the entire dataset. If “False”, it is impossible to make predictions using this GridSearchCV instance
after fitting.
如果 refit=False,clf.fit()
将无效,因为管道内的 GridSearchCV 对象将在 fit()
后重新初始化。
当 refit=True
时,GridSearchCV 将使用 fit()
中传递的整个数据的最佳评分参数组合进行重新拟合。
所以如果你要做管道,只看网格搜索的分数,那么refit=False
才合适。如果要调用clf.predict()
方法,必须使用refit=True
,否则会抛出Not Fitted错误。
在当前版本的 scikit-learn (0.18.1) 中无法执行此操作。 github 项目提出了修复:
对于那些偶然发现有点不同的问题的人,我也遇到过。
假设您有这个管道:
classifier = Pipeline([
('vectorizer', CountVectorizer(max_features=100000, ngram_range=(1, 3))),
('clf', RandomForestClassifier(n_estimators=10, random_state=SEED, n_jobs=-1))])
然后,在指定参数时,您需要包含您用于估算器的这个“clf_”名称。所以参数网格将是:
params={'clf__max_features':[0.3, 0.5, 0.7],
'clf__min_samples_leaf':[1, 2, 3],
'clf__max_depth':[None]
}
我正在使用 scickit-learn 来调整模型超参数。我正在使用管道将预处理与估算器链接起来。我的问题的简单版本如下所示:
import numpy as np
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
grid = GridSearchCV(make_pipeline(StandardScaler(), LogisticRegression()),
param_grid={'logisticregression__C': [0.1, 10.]},
cv=2,
refit=False)
_ = grid.fit(X=np.random.rand(10, 3),
y=np.random.randint(2, size=(10,)))
在我的例子中,预处理(玩具示例中的 StandardScale() 是什么)非常耗时,我没有调整它的任何参数。
因此,当我执行示例时,StandardScaler 被执行了 12 次。 2 fit/predict * 2 个简历 * 3 个参数。但是每次为参数 C 的不同值执行 StandardScaler 时,它 returns 相同的输出,所以它会更有效率,计算一次,然后只 运行 估计器部分管道。
我可以手动拆分预处理(未调整超参数)和估算器之间的管道。但是要对数据进行预处理,我应该只提供训练集。所以,我将不得不手动实现拆分,根本不使用 GridSearchCV。
在使用 GridSearchCV 时是否有 simple/standard 方法来避免重复预处理?
更新:
理想情况下,不应使用以下答案,因为它会导致评论中讨论的数据泄漏。在此答案中,GridSearchCV
将调整已由 StandardScaler
预处理的数据的超参数,这是不正确的。在大多数情况下这应该无关紧要,但对缩放过于敏感的算法会给出错误的结果。
本质上,GridSearchCV 也是一个估算器,实现了管道使用的 fit() 和 predict() 方法。
所以代替:
grid = GridSearchCV(make_pipeline(StandardScaler(), LogisticRegression()),
param_grid={'logisticregression__C': [0.1, 10.]},
cv=2,
refit=False)
这样做:
clf = make_pipeline(StandardScaler(),
GridSearchCV(LogisticRegression(),
param_grid={'logisticregression__C': [0.1, 10.]},
cv=2,
refit=True))
clf.fit()
clf.predict()
它会做的是,只调用 StandardScalar() 一次,一次调用 clf.fit()
而不是你描述的多次调用。
编辑:
当在管道内使用 GridSearchCV 时,将改装更改为 True
。作为 mentioned in documentation:
refit : boolean, default=True Refit the best estimator with the entire dataset. If “False”, it is impossible to make predictions using this GridSearchCV instance after fitting.
如果 refit=False,clf.fit()
将无效,因为管道内的 GridSearchCV 对象将在 fit()
后重新初始化。
当 refit=True
时,GridSearchCV 将使用 fit()
中传递的整个数据的最佳评分参数组合进行重新拟合。
所以如果你要做管道,只看网格搜索的分数,那么refit=False
才合适。如果要调用clf.predict()
方法,必须使用refit=True
,否则会抛出Not Fitted错误。
在当前版本的 scikit-learn (0.18.1) 中无法执行此操作。 github 项目提出了修复:
对于那些偶然发现有点不同的问题的人,我也遇到过。
假设您有这个管道:
classifier = Pipeline([
('vectorizer', CountVectorizer(max_features=100000, ngram_range=(1, 3))),
('clf', RandomForestClassifier(n_estimators=10, random_state=SEED, n_jobs=-1))])
然后,在指定参数时,您需要包含您用于估算器的这个“clf_”名称。所以参数网格将是:
params={'clf__max_features':[0.3, 0.5, 0.7],
'clf__min_samples_leaf':[1, 2, 3],
'clf__max_depth':[None]
}