Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Градиентный бустинг: XGBoost и LightGBM на практике

Градиентный бустинг: XGBoost и LightGBM на табличных данных

Градиентный бустинг: как работают XGBoost и LightGBM, ключевые параметры, обучение и регуляризация, сравнение на табличных задачах.

Прямой ответ

Градиентный бустинг строит ансамбль деревьев последовательно: каждое следующее дерево приближает антиградиент функции потерь по текущему предсказанию. На табличных данных это до сих пор самый сильный «дефолтный» подход: он не требует масштабирования признаков, терпим к пропускам и нелинейностям и быстро обучается.

Ключевые различия реализаций:

  • XGBoost. Классический уровень за уровнем; исторически точнее на небольших данных, хорошо регуляризуется. Поддерживает гистограммный метод (tree_method="hist"), который заметно ускоряет обучение.
  • LightGBM. Растит деревья leaf-wise (по лучшему листу, а не по уровню), использует гистограммы и GOSS/EFB. Обычно быстрее на больших выборках и даёт сопоставимое качество, но склонен к переобучению на малых данных без ограничения глубины.

Параметры, которые действительно влияют:

Параметр XGBoost LightGBM Что делает
Число деревьев n_estimators num_iterations Ёмкость ансамбля
Скорость обучения learning_rate learning_rate Шаг; меньше — стабильнее, но нужно больше деревьев
Глубина / листья max_depth num_leaves, max_depth Сложность дерева
Доля данных subsample bagging_fraction Регуляризация через подвыборку строк
Доля признаков colsample_bytree feature_fraction Регуляризация через подвыборку колонок
Регуляризация reg_lambda, reg_alpha lambda_l2, lambda_l1 Штраф на веса листьев

Базовый рецепт: learning_rate 0.03–0.1, число деревьев подбирается ранней остановкой, глубина 4–8 (или num_leaves 15–63), доли 0.7–0.9.

import lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

X_tr, X_va, y_tr, y_va = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
model = lgb.LGBMClassifier(
    learning_rate=0.05, num_iterations=2000, num_leaves=31,
    subsample=0.8, colsample_bytree=0.8, random_state=42, n_jobs=-1,
)
model.fit(X_tr, y_tr, eval_set=[(X_va, y_va)], eval_metric="auc",
          callbacks=[lgb.early_stopping(100, verbose=False)])
print(roc_auc_score(y_va, model.predict_proba(X_va)[:, 1]), model.best_iteration_)

Практика: что делать по шагам

  1. Начните с baseline. learning_rate=0.05, ранняя остановка, остальные параметры по умолчанию. Это точка отсчёта, без которой подбор параметров бессмыслен.
  2. Ранняя остановка обязательна. Она заменяет ручной подбор числа деревьев и защищает от переобучения. Важно: валидационный набор не должен участвовать в подборе других параметров повторно — иначе оценка оптимистична.
  3. Затем глубина/листья и доли. Это самые влиятельные параметры после скорости обучения.
  4. Проверяйте важность признаков. Высокая важность одного признака при слабом качестве — повод проверить утечку данных.
  5. На дисбалансе настройте веса. Механика и метрики — в статье про дисбаланс классов.
  6. Корректно оценивайте качество. Одна валидационная выборка даёт шумную оценку; надёжнее кросс-валидация — см. кросс-валидацию и подбор гиперпараметров.

Практические замечания:

  • Пропуски. Обе библиотеки обрабатывают NaN нативно, но поведение обученной модели на пропусках стоит проверить: если в проде пропусков больше, качество может отличаться.
  • Категориальные признаки. LightGBM поддерживает их напрямую (categorical_feature), XGBoost — начиная с 2.x через enable_categorical. В остальных случаях нужно кодирование.
  • Число потоков. n_jobs=-1 не всегда оптимален: на ноутбуке с троттлингом иногда быстрее ограничение числа потоков. Контекст работы без GPU — в статье про sklearn без GPU.
  • Воспроизводимость. Фиксируйте random_state и версии библиотек; разные версии могут давать разные результаты на тех же данных.

Диагностика переобучения по кривым. Стройте кривые обучения: метрика на обучении и на валидации по числу деревьев. Расхождение, которое растёт после определённого момента, указывает на точку, где стоит остановить обучение. Если кривая валидации выходит на плато рано, увеличивать ёмкость бессмысленно — ограничение в данных или признаках, а не в модели.

Работа с категориальными признаками. Прямая поддержка категорий удобна, но требует аккуратности: категории с малым числом наблюдений дают неустойчивые разбиения. Практика — объединять редкие категории в «прочие» до обучения и фиксировать этот список как часть пайплайна, иначе в проде появится неизвестная модель категория.

Практический сценарий: качество на тесте 0.94, в проде 0.76

Контекст: модель скоринга обращений; после выкатки качество заметно ниже ожидаемого.

  1. Проверка утечки. Важность признака resolved_at_hours оказалась максимальной. Этот признак появляется только после закрытия обращения, то есть в момент предсказания его ещё нет.
  2. Вторая причина. Обучающая выборка была собрана по состоянию на конец месяца, а часть признаков (например, число повторных обращений) рассчитана «на будущее» относительно события.
  3. Исправление. Удалили признаки, недоступные в момент предсказания; пересобрали выборку с учётом времени события; добавили проверку списка признаков на доступность.
  4. Результат. Офлайн-качество снизилось до 0.85, но совпало с онлайн-результатом. Разрыв исчез — это и есть признак корректной модели.
  5. Профилактика. Список признаков проходит ревью на «доступность в момент запроса»; процедура включена в пайплайн обучения.

Вывод: бустинг легко «выучивает» утечку данных и показывает выдающиеся офлайн-метрики. Проверка доступности признаков важнее подбора параметров.

FAQ

Что выбрать: XGBoost или LightGBM? На больших таблицах LightGBM обычно быстрее при сопоставимом качестве. На малых данных XGBoost с ограниченной глубиной устойчивее к переобучению. Решение стоит принимать по замеру на своих данных, а не по общим рекомендациям.

Почему LightGBM переобучается на малых выборках? Из-за leaf-wise роста: дерево углубляется в наиболее выигрышный лист, что даёт сложные деревья при малом объёме данных. Лечится ограничением num_leaves, min_data_in_leaf и увеличением регуляризации.

Нужно ли масштабировать признаки? Нет: деревья работают с порядком значений, а не с их масштабом. Масштабирование нужно для линейных моделей и нейросетей, но не для бустинга.

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

Источники: XGBoost docs, LightGBM docs, scikit-learn ensemble — ссылки в шапке.