Classical machine learning
XGBoost, LightGBM and CatBoost
Three libraries implement gradient boosting with different engineering. LightGBM is a fast default, CatBoost handles categoricals well, and features still matter more than the logo.
XGBoost, LightGBM and CatBoost all implement gradient boosting with clever engineering. The quality gap between them is usually smaller than the gap from feature quality and honest validation. Pick one, then spend time on the pipeline.
Concept
Histogram splits bin each feature (for example 255 bins) and search split points over bin boundaries. Quality loss versus exact greedy search is tiny. Speed gains are large.
The big idea
| Library | Strengths | Categoricals / missing |
|---|---|---|
| XGBoost | Mature, exact/approx splits, huge ecosystem | Missing learned. Cats often need encoding |
| LightGBM | Fast histogram algorithm, leaf-wise growth, great on large data | Native categorical support. Missing OK |
| CatBoost | Ordered target statistics for categoricals, strong defaults | Best-in-class categorical handling |
Default to LightGBM for large tabular jobs (speed plus quality). Use CatBoost when you have many categorical columns and little time to encode. Use XGBoost when the org already standardizes on it or you need a specific feature.
LightGBM’s leaf-wise growth expands the leaf with the best loss reduction (versus level-wise breadth-first). That fits faster but can overfit small data, so num_leaves and min_data_in_leaf matter.
You do not need to reimplement histograms. You do need to know that "exact" versus "hist" is an engineering trade-off already decided for you in sensible defaults.
Walking through a tuning recipe
Hyperparameter search expands to fill the time you give it. A disciplined order:
- Fixes first: time/group split, leakage check, class weight /
scale_pos_weight, eval metric = PR-AUC or log loss. - Learning rate plus trees: set
learning_ratein{0.03, 0.05, 0.1}. Setn_estimatorshigh (2000–5000). Early stop on validation. - Tree shape:
num_leaves∈{15, 31, 63}(LightGBM) ormax_depth∈{4, 6, 8}(XGBoost). - Row/column sampling:
subsampleandcolsample_bytreearound0.7–0.9. - Regularization:
min_data_in_leaf,lambda_l2. Increase if train ≪ val gap.
Only then try fancy search (Optuna) on a narrow band.
import lightgbm as lgb
from sklearn.datasets import make_classification
from sklearn.metrics import average_precision_score
from sklearn.model_selection import train_test_split
X, y = make_classification(
n_samples=20_000, n_features=30, weights=[0.95, 0.05], random_state=0
)
X_tr, X_tmp, y_tr, y_tmp = train_test_split(X, y, test_size=0.4, stratify=y, random_state=0)
X_va, X_te, y_va, y_te = train_test_split(X_tmp, y_tmp, test_size=0.5, stratify=y_tmp, random_state=0)
model = lgb.LGBMClassifier(
n_estimators=5000, learning_rate=0.05, num_leaves=31,
subsample=0.8, colsample_bytree=0.8, random_state=0, verbose=-1,
)
model.fit(
X_tr, y_tr, eval_set=[(X_va, y_va)], eval_metric="average_precision",
callbacks=[lgb.early_stopping(50), lgb.log_evaluation(0)],
)
ap = average_precision_score(y_te, model.predict_proba(X_te)[:, 1])
print("PR-AUC", round(ap, 3), "best_iter", model.best_iteration_)On a real churn dataset the same pattern applies: time-based split, early stopping on validation PR-AUC or log loss, then one shot on test.
Churn, 2% positives, 400k rows. scale_pos_weight ≈ 49. learning_rate=0.05, early stopping patience 50, num_leaves=31. Best iteration lands at 412 trees. Validation PR-AUC 0.31 versus logistic 0.24 versus heuristic 0.18. Test PR-AUC 0.29 — small drop, acceptable. SHAP says days_since_login and tickets_30d dominate. No leaked cancel_reason. Ship candidate.
Deep nets win when you have huge data, rich unstructured inputs, or need end-to-end representation learning. Hybrid stacks (neural embeddings plus GBDT on top) appear in large ranking systems. See ranking. Do not switch from LightGBM to an MLP because of fashion.
Common mistakes
- Picking the library before checking leakage. Features still win.
- Tuning 20 knobs before early stopping works. Fix splits and the metric first.
- Using default 0.5 as a threshold on 2% positives. Freeze the threshold from validation.
Check yourself
- You have many raw categoricals and little encoding time. Which library is the usual pick? Answer: CatBoost, because of ordered target statistics.
- Why does LightGBM need
num_leavesandmin_data_in_leafmore than a level-wise booster? Answer: Leaf-wise growth can grow a few leaves very deep and overfit small data.
Key takeaways
- LightGBM / XGBoost / CatBoost differ mainly in speed and categorical handling. Features matter more.
- Histogram splits are why modern GBDTs are fast.
- Tune learning rate with early stopping first, then tree shape, then sampling.
- GBDTs remain the tabular default. Deep nets need a concrete reason.
Further learning
XGBoost: A Scalable Tree Boosting SystemTree boosting is a highly effective and widely used machine learning method. In this paper, we describe a scalable end-to-end tree boosting system called XGBoost, which is used widely by data scientists to achieve sta…arXiv.org
LightGBM ParametersParameters — LightGBM 4.7.0.99 documentationlightgbm.readthedocs.io
Back to the map: trees and gradient boosting.
Related
Trees and gradient boosting
Decision trees, random forests and XGBoost/LightGBM: still the best default for tabular data.
Gradient boosting
Boosting adds shallow trees one after another, each fitting the residual of the ensemble so far. Shrinkage and early stopping keep the sum from hugging noise.
Features and data preparation
Turning raw data into model inputs without leaking the future. Covers scaling, encoding, missing values, time windows, target encoding and class imbalance, and keeping training and serving identical.