将 sklearn 的 GridSearchCV 与管道一起使用,只进行一次预处理

新手上路,请多包涵

我正在使用 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 时重复预处理?

原文由 Marc Garcia 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 404
2 个回答

更新:理想情况下,不应使用以下答案,因为它会导致评论中讨论的数据泄漏。在此答案中, 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()

所以如果你要做管道,只看网格搜索的分数,只有 refit=False 合适。如果要调用 clf.predict() 方法,必须使用 refit=True ,否则会报Not Fitted错误。

原文由 Vivek Kumar 发布,翻译遵循 CC BY-SA 4.0 许可协议

对于那些偶然发现一些不同问题的人,我也遇到过。

假设你有这个管道:

 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]
        }

原文由 Ayan Omarov 发布,翻译遵循 CC BY-SA 4.0 许可协议

推荐问题