簡體   English   中英

將 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 擬合/預測 * 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 項目上提出了一個修復:

https://github.com/scikit-learn/scikit-learn/issues/8830

https://github.com/scikit-learn/scikit-learn/pull/8322

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM