XGBoost стал одним из наиболее часто используемых инструментов в машинном обучении. Он состоит из ансамбля деревьев решений, где каждое новое дерево зависит от оценки предыдущего. Этот последовательный способ добавления классификаторов называется повышением, но в отличие от традиционного повышения, с XGBoost его можно запускать параллельно, поскольку при построении деревьев каждая ветвь обучается независимо.
Но, как и любой алгоритм машинного обучения, XGBoost также требует настройки гиперпараметров. Чтобы сделать это простым и эффективным способом, мы объединим его с GridSearchCV Scikit-Learn.
Гиперпараметры XGBoost
Есть несколько параметров, которые мы можем использовать при определении классификатора или регрессора XGBoost. Если вы хотите увидеть их все, посмотрите официальную документацию здесь. В этой статье мы рассмотрим только самые распространенные. Такие как:
- Learning_rate: скорость обучения. На каждом этапе повышения эти значения уменьшают вес новых функций, предотвращая переоснащение или локальный минимум. Это значение должно быть от 0 до 1. Значение по умолчанию - 0,3.
- max_depth: максимальная глубина дерева. Будьте осторожны, чем больше глубина, тем сложнее модель и ее будет легче переоснастить. Это значение должно быть целым числом больше 0 и иметь по умолчанию 6.
- n_estimators: количество деревьев в нашем ансамбле.
- гамма: термин регуляризации, связанный со сложностью модели. Это минимальная потеря, необходимая для раскола листа. Это может быть любое значение больше нуля, а значение по умолчанию - 0.
- colsample_bytree: представляет долю столбцов для подвыборки. Это связано со скоростью алгоритма и предотвращением переобучения. Значение по умолчанию - 1, но может быть любым числом от 0 до 1.
- лямбда: L2 регуляризация весов. Это способствует меньшему весу. По умолчанию 1, но это может быть любое значение.
- альфа: регуляризация L1 весов. Как и лямбда, это также способствует уменьшению веса. По умолчанию 1, но также может быть любое значение.
Оптимизация гиперпараметров
У каждой модели машинного обучения есть параметры, которые не оптимизируются в процессе обучения, гиперпараметры. Это означает, что нам нужно протестировать множество комбинаций вручную, чтобы найти оптимальные значения. Двумя наиболее распространенными методами являются поиск по сетке и случайный поиск.
Поиск по сетке
Самый простой способ найти оптимальные гиперпараметры - проверить каждую комбинацию гиперпараметров. Это называется поиском по сетке. Количество итераций - это произведение количества каждого гиперпараметра. Например: Предположим, мы хотим протестировать модель с 5 значениями гиперпараметра альфа, 10 для бета и 2 для гаммы. Поиск по сетке будет выполняться 5 * 10 * 2 = 100 итераций.
Случайный поиск
При случайном поиске, как следует из названия, вместо того, чтобы просматривать каждую комбинацию, мы просто случайным образом выбираем их. Количество итераций указывается перед запуском поиска.
Реализация
Чтобы прояснить ситуацию, давайте рассмотрим пример использования XGBoost с scikit-learn. Данные и процесс очистки, которые я использую здесь, такие же, как в предыдущей статье о сборке и вставке.
В этом примере мы будем использовать набор данных переписи 1994 года о доходах в США. Он содержит такую информацию, как семейное положение, возраст, вид работы и многое другое. В качестве целевого столбца у нас есть категориальный тип данных, который сообщает, если зарплата меньше или равна 50 тысячам в год (0) или нет (1). Давайте изучим DataFrame с помощью метода info Pandas:
RangeIndex: 32561 entries, 0 to 32560 Data columns (total 15 columns):age 32561 non-null int64 workclass 32561 non-null object fnlwgt 32561 non-null int64 education 32561 non-null object education_num 32561 non-null int64 marital_status 32561 non-null object occupation 32561 non-null object relationship 32561 non-null object race 32561 non-null object sex 32561 non-null object capital_gain 32561 non-null int64 capital_loss 32561 non-null int64 hours_per_week 32561 non-null int64 native_country 32561 non-null object high_income 32561 non-null int8 dtypes: int64(6), int8(1), object(8)
Как мы видим, есть числовые (int64 и int8) и категориальные (объектные) типы данных. Мы должны обрабатывать каждый тип отдельно, чтобы отправить его предиктору.
Загрузка и очистка данных
Сначала мы загружаем файл CSV и преобразуем целевой столбец в категориальный, поэтому, когда мы передаем все столбцы в конвейер, нам не нужно беспокоиться о целевом столбце.
import numpy as np import pandas as pd # Load CSV df = pd.read_csv('data/income.csv') # Convert target to categorical col = pd.Categorical(df.high_income) df["high_income"] = col.codes
В нашем наборе данных есть числовые и категориальные столбцы. Нам нужно сделать различную предварительную обработку в каждом из них. Числовые признаки необходимо нормализовать, а категориальные признаки - преобразовать в целые числа. Для этого мы определяем преобразователь для предварительной обработки наших данных в зависимости от его типа.
from sklearn.base import BaseEstimator, TransformerMixin from sklearn.preprocessing import MinMaxScaler class PreprocessTransformer(BaseEstimator, TransformerMixin): def __init__(self, cat_features, num_features): self.cat_features = cat_features self.num_features = num_features def fit(self, X, y=None): return self def transform(self, X, y=None): df = X.copy() # Treat ? workclass as unknown df.loc[df['workclass'] == '?', 'workclass'] = 'Unknown' # Too many categories, just convert to US and Non-US df.loc[df['native_country']!='United-States','native_country']='non_usa' # Convert columns to categorical for name in self.cat_features: col = pd.Categorical(df[name]) df[name] = col.codes # Normalize numerical features scaler = MinMaxScaler() df[self.num_features] = scaler.fit_transform(df[num_features]) return df
Затем данные разделяются на обучающие и тестовые, чтобы позже мы могли увидеть, обобщена ли наша модель на невидимые данные.
from sklearn.model_selection import train_test_split # Split the dataset into training and testing X_train, X_test, y_train, y_test = train_test_split( df.drop('high_income', axis=1), df['high_income'], test_size=0.2, random_state=42, shuffle=True, stratify=df['high_income'] )
Строительство трубопровода
Чтобы отправить данные в модель, ее необходимо очистить и подготовить. Для этого мы создаем конвейер с несколькими шагами. Первый шаг вызовет наш преобразователь предварительной обработки, второй выберет 10 лучших характеристик на основе хи-квадрат, а третий шаг - это сам классификатор.
from sklearn.pipeline import Pipeline from sklearn.feature_selection import SelectKBest, chi2 import xgboost as xgb # Get columns list for categorical and numerical categorical_features = df.select_dtypes('object').columns.tolist() numerical_features = df.select_dtypes('int64').columns.tolist() # Create a pipeline pipe = Pipeline([ ('preproc', PreprocTransformer(categorical_features, numerical_features)), ('fs', SelectKBest()), ('clf', xgb.XGBClassifier(objective='binary:logistic')) ])
Теперь мы определим наше пространство поиска для поиска по сетке. Здесь будут настраиваться гиперпараметры: n_estimators, learning_rate, max_depth, colsample_bytree и gamma strong. >. Всего получается 288 комбинаций. Мы также используем KFold с 10 разделениями в качестве перекрестной проверки и AUC и точность в качестве оценки.
from sklearn.model_selection import KFold, GridSearchCV from sklearn.metrics import accuracy_score, make_scorer # Define our search space for grid search search_space = [ { 'clf__n_estimators': [50, 100, 150, 200], 'clf__learning_rate': [0.01, 0.1, 0.2, 0.3], 'clf__max_depth': range(3, 10), 'clf__colsample_bytree': [i/10.0 for i in range(1, 3)], 'clf__gamma': [i/10.0 for i in range(3)], 'fs__score_func': [chi2], 'fs__k': [10], } ] # Define cross validation kfold = KFold(n_splits=10, random_state=42) # AUC and accuracy as score scoring = {'AUC':'roc_auc', 'Accuracy':make_scorer(accuracy_score)} # Define grid search grid = GridSearchCV( pipe, param_grid=search_space, cv=kfold, scoring=scoring, refit='AUC', verbose=1, n_jobs=-1 ) # Fit grid search model = grid.fit(X_train, y_train)
Оценки модели и матрицу неточностей можно получить следующим образом:
predict = model.predict(X_test) print('Best AUC Score: {}'.format(model.best_score_)) print('Accuracy: {}'.format(accuracy_score(y_test, predict))) print(confusion_matrix(y_test,predict))
Выход:
Best AUC Score: 0.9116424235417477 Accuracy: 0.8615077537233226 [[4621 324] [ 578 990]]
А лучшие параметры можно получить:
print(model.best_params_)
Которые:
- colsample_bytree: 0,2
- гамма: 0,2
- скорость обучения: 0,1
- max_depth: 3
- n_estimators: 200
Заключение
XGBoost - это гибкий и мощный алгоритм машинного обучения. Поиск оптимальных гиперпараметров имеет важное значение для получения максимальной отдачи. Одна из альтернатив - использовать поиск по сетке в других библиотеках, таких как scikit-learn.
Увидимся в следующий раз :)