XGBoost Hyperparameter Tuning · A Systematic Guide

Tuning XGBoost is sensitive to parameter ordering. Tuning parameters in the wrong order — or tuning everything at once — leads to suboptimal results and wasted compute. The established methodology tunes parameters in tiers, from most to least impactful.

The Tier System

Tier 1: Tree Structure (highest impact)

n_estimators and learning_rate are tuned together. Higher n_estimators requires lower learning_rate. The classic approach:

model = xgb.XGBRegressor(n_estimators=1000, learning_rate=0.01, early_stopping_rounds=50)
model.fit(X_train, y_train, eval_set=[(X_val, y_val)])
optimal_n = model.best_iteration  # e.g., 347

Then set n_estimators=optimal_n with a higher learning_rate and re-tune.

Tier 2: Regularization

max_depth (3–10), min_child_weight (1–10), gamma (0–5), lambda (0.1–10), alpha (0–1). These control overfitting. Tune together because they interact — deep trees need more regularization.

Tier 3: Subsampling

subsample (0.5–1.0), colsample_bytree (0.5–1.0), colsample_bylevel, colsample_bynode. These add randomness and reduce overfitting. Subsample of 0.8 is a good default.

Tier 4: Learning rate final

Reduce learning_rate and increase n_estimators proportionally for final model. Halving the learning rate typically requires doubling n_estimators.

Practical Search Strategies

xgboost-org 配图

xgboost-org 配图

Grid search: Exhaustive but exponential. Use only for Tier 1 (2 parameters max).

Random search: More efficient than grid search for 3+ parameters. Sample 50–200 combinations from reasonable ranges.

Bayesian optimization (Optuna, Hyperopt): Most efficient for 5+ parameters. Optuna’s TPESampler works well with XGBoost:

import optuna
def objective(trial):
    params = {
        'max_depth': trial.suggest_int('max_depth', 3, 12),
        'learning_rate': trial.suggest_float('lr', 0.01, 0.3, log=True),
        'subsample': trial.suggest_float('subsample', 0.5, 1.0),
        'lambda': trial.suggest_float('lambda', 0.1, 10, log=True),
    }
    model = xgb.XGBRegressor(**params, n_estimators=100, early_stopping_rounds=20)
    model.fit(X_train, y_train, eval_set=[(X_val, y_val)], verbose=False)
    return model.best_score
study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=50)

Common ranges:

  • max_depth: 3–10. Deeper = more complex. Start at 6.
  • learning_rate: 0.01–0.3. Lower = better generalization, more trees needed.
  • subsample: 0.5–1.0. 0.8 is the safe default.
  • colsample_bytree: 0.3–1.0. 0.5–0.8 often improves generalization.
  • min_child_weight: 1–10. Higher = more conservative. Important for imbalanced classification.
  • gamma: 0–5. Increase if tree depth is limited by regularization, not data.