Клієнт змінив вимоги на пізньому етапі: замість бінарної класифікації знадобилася мультикласова. Довелося перезбирати пайплайн з нуля. Виручили градієнтні бустинги — XGBoost, LightGBM та CatBoost. У проєкті зі скорингу клієнтів банку ми зіткнулися з дисбалансом класів та 500+ ознаками. Бустинги дозволили досягти AUC 0.92 без глибокого навчання. Ці алгоритми — робочі конячки ML для табличних структурованих даних. Вони домінують у Kaggle та production там, де нейронні мережі пасують: мало даних, багато категоріальних фіч, потрібна інтерпретованість. Вони ефективні на табличних даних з тисячами ознак, не вимагають нормалізації та стійкі до пропусків.
Типовий сценарій: дані — таблиця з пропусками, категоріальними колонками з високою кардинальністю та незбалансованим таргетом. Градієнтний бустинг з правильним налаштуванням виграє у лінійних моделей та випадкового лісу на 3-5% за AUC. Ми тестували гіпотези на історичних даних — прирости стабільні.
Які проблеми вирішуємо
Неоптимальні гіперпараметри знижують AUC на 3-5%. Ми використовуємо Optuna з ранньою зупинкою: 100 ітерацій за 10-30 хвилин на 1M рядків.
Категоріальні ознаки з високою кардинальністю. One-Hot Encoding плодить розрідженість. CatBoost вирішує це native, для LightGBM застосовуємо bayesian target encoding.
Інтерпретованість для бізнесу. SHAP-аналіз розкладає передбачення на внески ознак — обов'язкова вимога для кредитного скорингу або медицини. Як зазначає оригінальна стаття: XGBoost: A Scalable Tree Boosting System (Chen & Guestrin, 2016).
Дисбаланс класів — ще одна типова проблема. Бустинги зі зваженими вибірками та early stopping допомагають зберегти якість на рідкісних подіях.
Чому саме ці алгоритми?
LightGBM виграє за швидкістю: він навчається в 2-3 рази швидше за XGBoost на датасетах від 100K рядків. XGBoost стабільніший на розріджених даних і дає більш згладжені передбачення. CatBoost не вимагає кодування категорій — просто вкажіть список cat_features. В ансамблі вони перекривають слабкості один одного: stacking дає приріст AUC 0.5-2% відносно кращої одиночної моделі. Економія на обчислювальних ресурсах до 40% при використанні LightGBM.
| Критерій | XGBoost | LightGBM | CatBoost |
|---|---|---|---|
| Швидкість навчання | Середня | Висока | Висока |
| Категоріальні ознаки | Потрібен encoding | Потрібен encoding | Нативна підтримка |
| Пам'ять | Високе споживання | Низьке | Середнє |
| GPU підтримка | Так | Так | Так |
| Пропуски в даних | Нативно | Нативно | Нативно |
Як ми це робимо
Стек: Python 3.11, LightGBM 4.0, XGBoost 2.0, CatBoost 1.2, Optuna 3.5. Для великих даних використовуємо Dask або Spark, на яких бустинги працюють через distributed API. Типовий кейс: прогноз відтоку з 1 млн рядків і 200+ ознаками. Після підбору num_leaves=127, learning_rate=0.03, subsample=0.8 AUC зріс з 0.82 до 0.87. Окупність пілотного проєкту досягається за рахунок зростання точності прогнозів.
Як уникнути перенавчання?
Рання зупинка та регуляризація — ключові прийоми. Параметри reg_alpha, reg_lambda, min_child_samples контролюють складність моделі. Ми використовуємо крос-валідацію з 5 фолдами та моніторингом метрики на валідації.
Порівняння продуктивності
| Параметр | LightGBM | XGBoost (hist) | CatBoost |
|---|---|---|---|
| Час навчання (1M x 100 фіч) | 12 хв | 25 хв | 18 хв |
| AUC (дефолтні параметри) | 0.78 | 0.79 | 0.80 |
| AUC (Optuna optimised) | 0.84 | 0.84 | 0.85 |
SHAP-аналіз в деталях
SHAP-аналіз розкладає передбачення на внески кожної ознаки, що дозволяє зрозуміти, які фактори впливають на результат. Це critical для бізнес-завдань з вимогами до прозорості, наприклад, у кредитному скорингу або медичній діагностиці.Процес роботи
- Аналітика. Вивчаємо розподіли, викиди, кореляції.
- Feature engineering. Генеруємо ознаки на основі бізнес-логіки (ковзні середні, крос-таблиці).
- Пошук гіперпараметрів. Optuna з 100-200 ітераціями, крос-валідація StratifiedKFold.
- Навчання та валідація. Оцінюємо AUC, precision-recall, калібрування.
- Інтерпретація. SHAP summary plot та dependence plots для топ-10 фіч.
- Деплой. Експорт в ONNX або PMML, REST API на FastAPI, моніторинг дрейфу.
Реалізація
LightGBM: повний pipeline
import lightgbm as lgb from sklearn.model_selection import StratifiedKFold from sklearn.metrics import roc_auc_score import optuna def train_lgbm_with_cv(X: pd.DataFrame, y: pd.Series, n_splits: int = 5) -> lgb.LGBMClassifier: def objective(trial): params = { 'n_estimators': trial.suggest_int('n_estimators', 100, 1000), 'num_leaves': trial.suggest_int('num_leaves', 20, 300), 'max_depth': trial.suggest_int('max_depth', 3, 12), 'learning_rate': trial.suggest_float('learning_rate', 0.005, 0.1, log=True), 'subsample': trial.suggest_float('subsample', 0.6, 1.0), 'colsample_bytree': trial.suggest_float('colsample_bytree', 0.6, 1.0), 'reg_alpha': trial.suggest_float('reg_alpha', 1e-8, 10.0, log=True), 'reg_lambda': trial.suggest_float('reg_lambda', 1e-8, 10.0, log=True), 'min_child_samples': trial.suggest_int('min_child_samples', 5, 100), } cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) scores = [] for train_idx, val_idx in cv.split(X, y): model = lgb.LGBMClassifier(**params, random_state=42, verbose=-1) model.fit( X.iloc[train_idx], y.iloc[train_idx], eval_set=[(X.iloc[val_idx], y.iloc[val_idx])], callbacks=[lgb.early_stopping(50, verbose=False)] ) pred = model.predict_proba(X.iloc[val_idx])[:, 1] scores.append(roc_auc_score(y.iloc[val_idx], pred)) return np.mean(scores) study = optuna.create_study(direction='maximize') study.optimize(objective, n_trials=100, n_jobs=4) best_model = lgb.LGBMClassifier(**study.best_params, random_state=42) best_model.fit(X, y) return best_model def explain_model(model, X: pd.DataFrame): import shap explainer = shap.TreeExplainer(model) shap_values = explainer.shap_values(X) shap.summary_plot(shap_values, X, plot_type="bar") top_feature = X.columns[np.abs(shap_values).mean(0).argmax()] shap.dependence_plot(top_feature, shap_values, X) CatBoost з категоріальними ознаками
from catboost import CatBoostClassifier, Pool def train_catboost(X_train: pd.DataFrame, y_train: pd.Series, X_val: pd.DataFrame, y_val: pd.Series, cat_features: list[str]) -> CatBoostClassifier: train_pool = Pool(X_train, y_train, cat_features=cat_features) val_pool = Pool(X_val, y_val, cat_features=cat_features) model = CatBoostClassifier( iterations=1000, learning_rate=0.03, depth=6, l2_leaf_reg=3.0, bootstrap_type='Bayesian', bagging_temperature=1.0, eval_metric='AUC', use_best_model=True, early_stopping_rounds=100, random_seed=42, verbose=100 ) model.fit(train_pool, eval_set=val_pool) return model Як налаштувати стекінг для максимальної точності?
from sklearn.ensemble import StackingClassifier from sklearn.linear_model import LogisticRegression stacking = StackingClassifier( estimators=[ ('lgbm', lgb.LGBMClassifier(**lgbm_best_params)), ('xgb', XGBClassifier(**xgb_best_params)), ('catboost', CatBoostClassifier(**cat_best_params, verbose=0)), ], final_estimator=LogisticRegression(C=0.1), cv=5, stack_method='predict_proba' ) stacking.fit(X_train, y_train) Які помилки допускають при навчанні бустингів?
- Ігнорування категоріальних ознак: використовуйте CatBoost або правильний encoding.
- Недостатня валідація: StratifiedKFold для незбалансованих вибірок.
- Перенавчання: рання зупинка та регуляризація (
reg_alpha,reg_lambda).
Що входить в роботу (deliverables)
- Оптимізована модель з документованими гіперпараметрами.
- SHAP-звіт з топ-10 ознаками та їх впливом.
- REST API або ONNX-експорт.
- Деплой на production + моніторинг (дрейф даних, падіння метрик).
- Навчання команди замовника.
Строки орієнтовно
Від 5 робочих днів на прототип до 3 тижнів на production-пайплайн. Зв'яжіться з нами для консультації по вашому проєкту. Замовте пілотний проєкт, щоб оцінити приріст метрик. Вартість розраховується індивідуально. Отримайте консультацію по вашому проєкту — наші інженери допоможуть обрати оптимальний підхід.







