XGBoost с GridSearchCV, Scaling, PCA и ранней остановкой в ​​конвейере sklearn - PullRequest
0 голосов
/ 12 июня 2018

Я хочу объединить модель XGBoost с масштабированием ввода и сокращением функционального пространства с помощью PCA.Кроме того, гиперпараметры модели, а также количество компонентов, используемых в PCA, должны настраиваться с использованием перекрестной проверки.И чтобы предотвратить переоснащение модели, следует добавить раннюю остановку.

Для объединения различных шагов я решил использовать функции Pipeline от sklearn.

Вначале у меня были некоторые проблемы с проверкой того, что PCA также применяется к набору проверки.Но я думаю, что использование XGB__eval_set делает дело.

Код на самом деле работает без ошибок, но, кажется, работает вечно (в какой-то момент загрузка всех ядер ЦП падает до нуля, но процессы продолжают работать часами; в некоторых случаях пришлось прервать сеансточка).

from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.decomposition import PCA
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from xgboost import XGBRegressor   

# Train / Test split
X_train, X_test, y_train, y_test = train_test_split(X_with_features, y, test_size=0.2, random_state=123)

# Train / Validation split
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.2, random_state=123)

# Pipeline
pipe = Pipeline(steps=[("Scale", StandardScaler()),
                       ("PCA", PCA()),
                       ("XGB", XGBRegressor())])

# Hyper-parameter grid (Test only)
grid_param_pipe = {'PCA__n_components': [5],
                   'XGB__n_estimators': [1000],
                   'XGB__max_depth': [3],
                   'XGB__reg_alpha': [0.1],
                   'XGB__reg_lambda': [0.1]}

# Grid object
grid_search_pipe = GridSearchCV(estimator=pipe,
                                param_grid=grid_param_pipe,
                                scoring="neg_mean_squared_error",
                                cv=5,
                                n_jobs=5,
                                verbose=3)

# Run CV
grid_search_pipe.fit(X_train, y_train, XGB__early_stopping_rounds=10, XGB__eval_metric="rmse", XGB__eval_set=[[X_val, y_val]])

1 Ответ

0 голосов
/ 24 августа 2018

Проблема в том, что для метода fit требуется набор оценки, созданный извне, но мы не можем создать его до преобразования конвейером.

Это немного глупо, но идея состоит в том, чтобы создать тонкую оболочку для регрессора / классификатора xgboost, которая подготовит набор для оценки внутри.

from sklearn.base import BaseEstimator
from sklearn.model_selection import train_test_split
from xgboost import XGBRegressor, XGBClassifier

class XGBoostWithEarlyStop(BaseEstimator):
    def __init__(self, early_stopping_rounds=5, test_size=0.1, 
                 eval_metric='mae', **estimator_params):
        self.early_stopping_rounds = early_stopping_rounds
        self.test_size = test_size
        self.eval_metric=eval_metric='mae'        
        if self.estimator is not None:
            self.set_params(**estimator_params)

    def set_params(self, **params):
        return self.estimator.set_params(**params)

    def get_params(self, **params):
        return self.estimator.get_params()

    def fit(self, X, y):
        x_train, x_val, y_train, y_val = train_test_split(X, y, test_size=self.test_size)
        self.estimator.fit(x_train, y_train, 
                           early_stopping_rounds=self.early_stopping_rounds, 
                           eval_metric=self.eval_metric, eval_set=[(x_val, y_val)])
        return self

    def predict(self, X):
        return self.estimator.predict(X)

class XGBoostRegressorWithEarlyStop(XGBoostWithEarlyStop):
    def __init__(self, *args, **kwargs):
        self.estimator = XGBRegressor()
        super(XGBoostRegressorWithEarlyStop, self).__init__(*args, **kwargs)

class XGBoostClassifierWithEarlyStop(XGBoostWithEarlyStop):
    def __init__(self, *args, **kwargs):
        self.estimator = XGBClassifier()
        super(XGBoostClassifierWithEarlyStop, self).__init__(*args, **kwargs)

Ниже приведен тест.

from sklearn.datasets import load_diabetes
from sklearn.pipeline import Pipeline
from sklearn.decomposition import PCA
from sklearn.model_selection import GridSearchCV

x, y = load_diabetes(return_X_y=True)
print(x.shape, y.shape)
# (442, 10) (442,)

pipe = Pipeline([
    ('pca', PCA(5)),
    ('xgb', XGBoostRegressorWithEarlyStop())
])

param_grid = {
    'pca__n_components': [3, 5, 7],
    'xgb__n_estimators': [10, 20, 30, 50]
}

grid = GridSearchCV(pipe, param_grid, scoring='neg_mean_absolute_error')
grid.fit(x, y)
print(grid.best_params_)

Если запрашивать функциональные запросы у разработчиков, самое простое расширение, которое нужно сделать, - это позволить XGBRegressor создавать оценочный набор внутри, если он не предоставлен.Таким образом, нет необходимости в расширении scikit-learn (я думаю).

...