[英]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.