#python #scikit-learn
#python #scikit-learn
Вопрос:
Долгосрочный пользователь R, изучающий Python. Я пытаюсь использовать GridSearch, чтобы попробовать разное количество компонентов для шага PCA в конвейере, а также для нескольких оценок. Я думал, что приведенный ниже код выполняет это (используя GridSearch
документацию плюс другие источники), но результат best_params_
не имеет параметров предварительной обработки и параметров оценки; вместо этого он печатает {'prep2__pcadtm__n_components': 3}
, что указывает мне, что его код не выполняет то, что я думал.
- Является ли следующий код способом проверки предварительной обработки с несколькими гиперпараметрами и несколькими оценками (плюс гиперпараметры) в одном и том же GridSearch? Если нет …
- Как я могу включить предварительную обработку с несколькими гиперпараметрами и несколькими оценками (плюс гиперпараметры) в один и тот же поиск по сетке?
MWE
## Dependencies
import seaborn as sns
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.compose import ColumnTransformer
from sklearn.neighbors import KNeighborsClassifier
from imblearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestClassifier
## load data set
df = sns.load_dataset('mpg').drop(["name"], axis = 1).dropna()
## Factoize the outcome
factor = pd.factorize(df['origin'])
df.origin = factor[0]
definitions = factor[1]
outcome_order = definitions.tolist()
X = df.loc[:, ~df.columns.isin(['origin'])]
y = df.iloc[:,7].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.20, random_state = 21)
scaler = StandardScaler()
pca = PCA(n_components = 2)
dtm_i = list(range(2, len(X_train.columns)))
dtm_i2 = list(range(0, len(X_train.columns)-2))
preprocess = ColumnTransformer(transformers=[('scaler', scaler, dtm_i)], remainder='passthrough')
preprocess2 = ColumnTransformer(transformers=[('pcadtm', pca, dtm_i2)], remainder='passthrough')
pipeline = Pipeline([
('prep', preprocess),
('prep2', preprocess2),
('clf', RandomForestClassifier())
])
search_space = [
{
'prep2__pcadtm__n_components': [2, 3]
},
{
'clf': [RandomForestClassifier()],
'clf__max_depth': [5, 15]
},
{
'clf': [KNeighborsClassifier()],
'clf__n_neighbors' : [2, 3]
}
]
# Create grid search
grid_imba = GridSearchCV(
estimator = pipeline,
param_grid = search_space,
scoring = 'accuracy',
cv = 3,
return_train_score = True
)
## Fit the model using all the different estimators
grid_imba.fit(X_train, y_train);
## Extract best
best_params = grid_imba.best_params_
print(best_params)
##{'prep2__pcadtm__n_components': 3}
Я думал, что GridSearch
это создаст 2 и 3 набора данных компонентов PCA, а затем передаст это следующему шагу с оценками. В свою очередь, оба вывода PCA будут протестированы со случайным лесом, а затем KNN [каждый из которых имеет 2 гиперпараметра. Значение 2 (наборы данных PCA для 2 и 3 компонентов) X 2 (оценки) X 2 (гиперпараметры для каждой оценки) = 8 тестируемых моделей]. Я думаю, что я не прав.
Наконец, для повышения эффективности было бы лучше, если prep2
бы шаг не вычислялся каждый раз при попытке создания новой оценки.
Ответ №1:
Действительно, когда param_grid
есть список словарей, поиск происходит по объединению сеток, сгенерированных каждым словарем. Таким образом, ваш код фактически проверяет шесть комбинаций гиперпараметров:
- PCA dim 2, глубина randomForest по умолчанию = Нет
- PCA dim 3, глубина randomForest по умолчанию = Нет
- Значения по умолчанию для PCA (dim2), глубина случайного леса 5
- Значения по умолчанию для PCA (dim2), глубина случайного леса 15
- PCA по умолчанию (dim2), KNN k=2
- PCA по умолчанию (dim2), KNN k=3
Вам понадобится что-то вроде
search_space = {
'prep2__pcadtm__n_components': [2, 3],
'clf': [RandomForestClassifier(max_depth=5),
RandomForestClassifier(max_depth=15),
KNeighborsClassifier(n_neighbors=2),
KNeighborsClassifier(n_neighbors=3)],
}
В зависимости от ваших реальных потребностей, это, конечно, может оказаться громоздким, чтобы перечислить все комбинации гиперпараметров, которые вы хотите для каждой отдельной модели. В этом случае может быть проще всего вложить поиск:
rf_gs = GridSearchCV(
estimator=RandomForestClassifier(),
param_grid={'max_depth': [5, 15]},
)
kn_gs = GridSearchCV(
estimator=KNeighborsClassifier(),
param_grid={'n_neighbors': [2, 3]},
)
pipeline = Pipeline([
('prep', preprocess),
('prep2', preprocess2),
('clf', RandomForestClassifier())
])
search = GridSearchCV(
estimator=pipeline,
param_grid={
'prep2__pcadtm__n_components': [2, 3],
'clf': [rf_gs, kn_gs],
},
scoring = 'accuracy',
cv = 3,
return_train_score = True
)
Это также приводит к меньшему количеству вычислений препроцессоров. Но смотрите Также memory
параметр Pipeline
.
Кроме того, обратите внимание, что этот подход довольно сильно изменяет cv-сгибы. Если вам нужен «плоский» поиск, возможно, напишите быстрый скрипт для создания более длинного списка в первом подходе.
Комментарии:
1. Отлично! Спасибо за правильный подход, альтернативу (2-й подход проще для меня) и особенно объяснение того, что на самом деле происходило. Очень полезный ответ для формирования моей ментальной концепции. Спасибо, что нашли время поделиться своими знаниями и опытом. Очень признателен!