Используйте 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 параметра. Но каждый раз, когда StandardScaler выполняется для другого значения параметра C, он возвращает тот же результат, поэтому было бы гораздо более эффективно вычислять его один раз, а затем просто запускать часть оценки конвейера.
Я могу вручную разделить конвейер между предварительной обработкой (не настроенными гипер-параметрами) и оценкой. Но чтобы применить предварительную обработку данных, я должен предоставить только набор тренировок. Таким образом, я должен был бы реализовать разрывы вручную, и вообще не использовать GridSearchCV.
Есть ли простой/стандартный способ избежать повторения предварительной обработки при использовании GridSearchCV?
Ответы
Ответ 1
По существу, GridSearchCV также является оценкой, реализующей методы fit() и pred(), используемые конвейером.
Итак, вместо:
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()
вместо нескольких вызовов, как вы описали.
Edit:
Изменено обновление до True
, когда GridSearchCV используется внутри конвейера. Как упомянутый в документации:
refit: boolean, default = True Установите лучшую оценку всего набора данных. Если "False", невозможно сделать прогнозы с использованием этого экземпляра GridSearchCV после установки.
Если refit = False, clf.fit()
не будет иметь эффекта, потому что объект GridSearchCV внутри конвейера будет повторно инициализирован после fit()
.
Когда refit=True
, GridSearchCV будет переоборудован с лучшей комбинацией параметров оценки для всех данных, которые передаются в fit()
.
Итак, если вы хотите сделать конвейер, просто чтобы увидеть результаты поиска сетки, только тогда подходит refit=False
. Если вы хотите вызвать метод clf.predict()
, необходимо использовать refit=True
, иначе будет выведена ошибка Not Fitted.
Ответ 2
Это невозможно сделать в текущей версии scikit-learn (0.18.1). В проекте github было предложено исправление:
https://github.com/scikit-learn/scikit-learn/issues/8830
https://github.com/scikit-learn/scikit-learn/pull/8322
Ответ 3
Для тех, кто наткнулся на немного другую проблему, которая у меня тоже была.
Предположим, у вас есть этот конвейер:
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]
}