У меня есть такие данные (столбцы):
| year-month | client_id | Y | X1.. Xn |
Где Y
, если клиент client_id
купил товар в данном year-month
. А X
— это объясняющие переменные. У меня есть месячные данные за два года, и я правильно выполнил разделение с помощью TimeSeriesSplit()
, указанного в ответе это. Проблема сейчас в том, что я хочу сделать GridSearchCV()
на этом расколе, пробуя разные модели (RF
, XGBoostClassifier()
, LightGBM()
и т. д.) с разными гиперпараметрами, но я не могу найти способ использовать GridSearchCV()
с сплит сделан.
Какие-либо предложения?
Предполагая, что у вас есть splits
df на основе вопроса это.
Сначала сохраните индексы для каждого Fold в массивы кортежей (train, test), то есть:
[(train_indices, test_indices), # 1stfold
(train_indices, test_indices)] # 2nd fold etc
Следующий код сделает это:
custom_cv = []
for FOLD_train,FOLD_test in zip(splits['train'],splits['test']):
custom_cv.append((np.array(FOLD_train.index.values.tolist()),np.array(FOLD_test.index.values.tolist())))
вы можете использовать GridSearchCV()
следующим образом:
Здесь мы создаем словарь с функциями классификатора и еще один словарь со списком параметров.
Это всего лишь пример. Обязательно ограничьте пространство поиска при тестировании.
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
from xgboost import XGBRegressor
dict_classifiers = {
"Random Forest": RandomForestClassifier(),
"Gradient Boosting Classifier": GradientBoostingClassifier(),
"Linear SVM": SVC(),
"XGB": XGBRegressor(),
"Logistic Regression": LogisticRegression(),
"Nearest Neighbors": KNeighborsClassifier(),
"Decision Tree": DecisionTreeClassifier(),
}
params = {
"Random Forest": {"max_depth": range(5, 30, 5), "min_samples_leaf": range(1, 30, 2),
"n_estimators": range(100, 2000, 200)},
"Gradient Boosting Classifier": {"learning_rate": [0.001, 0.01, 0.1], "n_estimators": range(1000, 3000, 200)},
"Linear SVM": {"kernel": ["rbf", "poly"], "gamma": ["auto", "scale"], "degree": range(1, 6, 1)},
"XGB": {'min_child_weight': [1, 5, 10],
'gamma': [0.5, 1, 1.5, 2, 5],
'subsample': [0.6, 0.8, 1.0],
'colsample_bytree': [0.6, 0.8, 1.0],
'max_depth': [3, 4, 5], "n_estimators": [300, 600],
"learning_rate": [0.001, 0.01, 0.1],
},
"Logistic Regression": {'penalty': ['none', 'l2'], 'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000]},
"Nearest Neighbors": {'n_neighbors': [3, 5, 11, 19], 'weights': ['uniform', 'distance'], 'metric': ['euclidean', 'manhattan']},
"Decision Tree": {'criterion': ['gini', 'entropy'], 'max_depth': np.arange(3, 15)},
}
for classifier_name in dict_classifiers.keys() & params:
print("training: ", classifier_name)
gridSearch = GridSearchCV(
estimator=dict_classifiers[classifier_name], param_grid=params[classifier_name], cv=custom_cv)
gridSearch.fit(df[['X']].to_numpy(), # shoud have shape of (n_samples, n_features)
df[['Y']].to_numpy().reshape((-1))) #this should be an array with shape (n_samples,)
print(gridSearch.best_score_, gridSearch.best_params_)
замените ['X']
на df.columns[pd.Series(df.columns).str.startswith('X')]
на gridsearch.fit
, если вы хотите передать все столбцы, начинающиеся с 'X'
в их имени (например, 'X1'
,'X2'
, ...) как train_set.
Я пытаюсь заставить его работать, но он показывает мне эту ошибку: AttributeError: 'DataFrame' object has no attribute 'X'
Я думаю, это потому, что вы предполагаете, что X — это только один столбец, хотя на самом деле их много. Я попытался решить эту проблему, заменив np.array(df.X.tolist())
на np.array(df[X_cols]tolist())
, где X_cols = X.columns
на X
в качестве фрейма данных с уже обработанными независимыми столбцами, но это говорит мне, что AttributeError: 'DataFrame' object has no attribute 'tolist'
. Что вы там пытаетесь сделать? Преобразование кадра данных в список, чтобы преобразовать его в матрицу?
@Chris Я обновил ответ с измененными аргументами на gridsearch.fit
, в основном вы можете либо заменить 'X'
на 'X1'
, 'X2'
, ..., чтобы передать несколько, либо использовать df.columns[pd.Series(df.columns).str.startswith('X')]
, чтобы вытащить все, что начинается с 'X'
в именах столбцов.
@Chris У тебя была возможность попробовать это?
Это сработало! Можете ли вы объяснить это, чтобы понять, почему это сработало? В частности, конструкция custom_cv
, логика использования .to_numpy()
и reshape((-1))
в gridSearch.fit()
. И, буду признателен, за ваше личное мнение о таком подходе к построению модели :) Спасибо!
custom_CV
— это просто попытка упорядочить индексы каждой складки так, как нужно gridsearchCV, то есть повторяемый список кортежей (поезд, тест), проверьте четвертый элемент параметра cv в документации Итерируемый выход (поезд, тест) разбивается на массивы индексов. То же самое относится и к отдыху, т.е. проверьте параметры X
и y
из fit
, им нужен массив (n_samples,n_features)
, а (n_samples,)
не работает. Итак, .to_numpy()
преобразовать список в массив NumPy, а reshape((-1))
- это ... @Chris
превращая его в (n_samples,1)
to (n_samples,)
. по мнению, вы можете оптимизировать гиперпараметры, используя этот подход, если ваши наборы достаточно малы, чтобы вся оптимизация занимала разумное время! в противном случае вы можете использовать подход train/test/dev set. какую модель выбрать полностью зависит от ваших данных, если у вас слишком много client_id, то вам следует рассмотреть другие подходы..... но я думаю, что вам не следует ожидать слишком большого увеличения конечной точности только с HPO, учитывайте данные- центральный подход, если это возможно, вы можете получить лучшие результаты, очистив данные, а не HPO. @Крис
Не могли бы вы сообщить мне, правильный ли ответ? в противном случае я постараюсь пересмотреть его, чтобы ответить на ваш вопрос