Common Mistakes & Best Practices for XGBoost
1. Tuning on the test set
Passing (X_test, y_test) in eval_set uses test labels to choose the number of trees. Repeated test scoring, threshold selection, and calibration have the same problem. Split the development data again for early stopping, or put the entire model-selection procedure inside an outer cross-validation loop.
2. Using obsolete estimator syntax
In XGBoost 3.4, eval_metric, early_stopping_rounds, and callbacks belong in XGBClassifier(...), XGBRegressor(...), or set_params. fit still receives eval_set, but does not create or stratify it. Examples that pass early_stopping_rounds directly to fit are version-stale.
After early stopping, scikit-learn estimator predictions use best_iteration. Native Booster.predict() can use all trees unless given the corresponding iteration_range or trained with a save-best callback. Do not silently mix those interfaces.
3. Scaling tree inputs by habit
Ordinary threshold-based tree splits are invariant to monotone rescaling, so standardization is usually unnecessary for XGBoost. Scale only for another pipeline component that needs it. Unneeded transformations add schema and leakage risk.
4. Treating codes as categories
Integer codes are numeric unless the data interface and enable_categorical=True identify them as categorical. Keep pandas categorical dtype and stable levels, serialize categorical models as JSON/UBJSON, and test unseen values. Fit one-hot or target encoders within training folds.
5. Searching an incoherent space
learning_rate, round count, depth/leaves, minimum Hessian, sampling, and penalties interact. Start with bounded log-scaled ranges where appropriate. Compare configurations using the same folds and budget; do not select one parameter on the test set and then tune another.
When early stopping is embedded in cross-validation, each fold needs its own validation subset. A single fixed eval_set passed through GridSearchCV is not fold-local and can contaminate the search.
6. Mishandling imbalance and probabilities
scale_pos_weight changes the fitted objective; it is not a universal calibration fix. Choose weights from training data according to costs or a documented heuristic, then evaluate ranking and probability calibration separately. Select any decision threshold on validation data.
7. Oversubscribing threads
Avoid combining a parallel search (n_jobs=-1) with every XGBoost fit also using all cores. Choose one parallelism layer, record thread counts, and include tuning and preprocessing time in comparisons.
8. Overinterpreting importance
Gain, weight, and cover answer different questions and can favor features with many split opportunities. Use held-out permutation importance or carefully specified SHAP analysis, check correlated features and stability, and never describe importance as causal effect.
Checklist
- Pin the tested XGBoost build and objective.
- Keep test data isolated from stopping, search, calibration, and thresholds.
- Preserve feature names, category dtypes, class order, and missing-value semantics.
- Compare simple baselines under identical splits and compute budgets.
- Log
best_iteration, metrics, seeds, hardware, and the final artifact format.