From: Jérôme Benoit Date: Tue, 6 Jan 2026 23:30:18 +0000 (+0100) Subject: refactor(xgboost): migrate to callback-based early stopping for API 3.x compatibility X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=0af16052d312cc0bea1e69f144b146cb181cb575;p=freqai-strategies.git refactor(xgboost): migrate to callback-based early stopping for API 3.x compatibility - Replace deprecated early_stopping_rounds parameter with EarlyStopping callback - Extract early_stopping_rounds from model parameters using pop() before instantiation - Configure callback with metric_name='rmse', data_name='validation_0', save_best=True - Reorganize LightGBM callback initialization for improved code readability - Maintains backward compatibility with eval_set validation approach - Ensures compatibility with XGBoost 3.1.2+ API requirements --- diff --git a/quickadapter/user_data/strategies/Utils.py b/quickadapter/user_data/strategies/Utils.py index dfc27c8..404fafa 100644 --- a/quickadapter/user_data/strategies/Utils.py +++ b/quickadapter/user_data/strategies/Utils.py @@ -1662,16 +1662,28 @@ def fit_regressor( if regressor == REGRESSORS[0]: # "xgboost" from xgboost import XGBRegressor + from xgboost.callback import EarlyStopping model_training_parameters.setdefault("random_state", 1) + early_stopping_rounds = None if has_eval_set: - model_training_parameters.setdefault( + early_stopping_rounds = model_training_parameters.pop( "early_stopping_rounds", _EARLY_STOPPING_ROUNDS_DEFAULT ) else: model_training_parameters.pop("early_stopping_rounds", None) + if early_stopping_rounds is not None and has_eval_set: + fit_callbacks.append( + EarlyStopping( + rounds=early_stopping_rounds, + metric_name="rmse", + data_name="validation_0", + save_best=True, + ) + ) + if trial is not None: model_training_parameters["random_state"] = ( model_training_parameters["random_state"] + trial.number @@ -1702,13 +1714,22 @@ def fit_regressor( model_training_parameters.setdefault("seed", 1) + early_stopping_rounds = None if has_eval_set: early_stopping_rounds = model_training_parameters.pop( "early_stopping_rounds", _EARLY_STOPPING_ROUNDS_DEFAULT ) else: model_training_parameters.pop("early_stopping_rounds", None) - early_stopping_rounds = None + + if early_stopping_rounds is not None: + fit_callbacks.append( + early_stopping( + stopping_rounds=early_stopping_rounds, + first_metric_only=True, + verbose=False, + ) + ) if trial is not None: model_training_parameters["seed"] = ( @@ -1721,15 +1742,6 @@ def fit_regressor( ) ) - if early_stopping_rounds is not None: - fit_callbacks.append( - early_stopping( - stopping_rounds=early_stopping_rounds, - first_metric_only=True, - verbose=False, - ) - ) - model = LGBMRegressor(objective="regression", **model_training_parameters) model.fit( X=X,