]> Piment Noir Git Repositories - freqai-strategies.git/commitdiff
refactor(xgboost): migrate to callback-based early stopping for API 3.x compatibility
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Tue, 6 Jan 2026 23:30:18 +0000 (00:30 +0100)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Tue, 6 Jan 2026 23:30:18 +0000 (00:30 +0100)
- 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

quickadapter/user_data/strategies/Utils.py

index dfc27c8b7a697001837a2c88c4c811601e5d42c1..404fafa5911e239ea77e0b0112129daa6ba23ade 100644 (file)
@@ -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,