[英]How to implement sklearn's Estimator interface for use in GridSearchCV pipeline?
[英]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 拟合/预测 * 2 cv * 3 参数。 但是每次针对参数 C 的不同值执行 StandardScaler 时,它都会返回相同的输出,因此计算一次会更有效率,然后只运行管道的估计器部分。
我可以在预处理(没有调整超参数)和估计器之间手动拆分管道。 但是要将预处理应用于数据,我应该只提供训练集。 因此,我必须手动实现拆分,而根本不使用 GridSearchCV。
是否有一种简单/标准的方法可以避免在使用 GridSearchCV 时重复预处理?
更新:理想情况下,不应使用以下答案,因为它会导致评论中讨论的数据泄漏。 在这个答案中, 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 时,将 refit 更改为True
。 如文档中所述:
refit : boolean, default=True 用整个数据集重新拟合最佳估计器。 如果为“False”,则在拟合后无法使用此 GridSearchCV 实例进行预测。
如果 refit=False, clf.fit()
将不起作用,因为管道内的 GridSearchCV 对象将在fit()
之后重新初始化。 当refit=True
,GridSearchCV 将使用fit()
传递的整个数据的最佳评分参数组合进行重新fit()
。
所以如果要制作pipeline,只看网格搜索的分数,只有refit=False
合适。 如果要调用clf.predict()
方法,必须使用refit=True
,否则会抛出 Not Fitted 错误。
对于那些偶然发现一些不同问题的人,我也遇到过。
假设你有这个管道:
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]
}
在当前版本的 scikit-learn (0.18.1) 中无法做到这一点。 在 github 项目上提出了一个修复:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.