CatBoost forecaster with real Bayesian tuning and SHAP.
This module provides ForecasterRecursiveCatBoostFull, which combines the CatBoost forecaster from spotforecast2-safe with Bayesian hyperparameter optimisation (Optuna) and SHAP-based feature importance from ForecasterRecursiveModelFull.
Examples
import numpy as npimport pandas as pdfrom catboost import CatBoostRegressorfrom spotforecast2_safe.forecaster.recursive import ForecasterRecursivefrom spotforecast2.models import ForecasterRecursiveCatBoostFullmodel = ForecasterRecursiveCatBoostFull(iteration=0, lags=3)# Swap in a tiny estimator so the example renders quickly.model.forecaster = ForecasterRecursive( estimator=CatBoostRegressor( iterations=5, depth=2, random_seed=1234, verbose=False, allow_writing_files=False, ), lags=3,)assert model.name =="catboost"assert model.n_trials ==10rng = np.random.default_rng(0)y = pd.Series( rng.random(30), index=pd.date_range("2023-01-01", periods=30, freq="h"),)model.fit(y=y)pred = model.forecaster.predict(steps=2)assertlen(pred) ==2print(f"name: {model.name}")print(f"n_trials: {model.n_trials}")print(f"forecast horizon: {len(pred)} steps")
╭─────────────────────────────── IgnoredArgumentWarning ───────────────────────────────╮│ The number of bins has been reduced from 10 to 8 due to duplicated edges caused by ││ repeated predicted values. ││││ Category : spotforecast2.exceptions.IgnoredArgumentWarning ││ Location : ││ /opt/hostedtoolcache/Python/3.13.14/x64/lib/python3.13/site-packages/spotforecast2_s ││ afe/preprocessing/_binner.py:259 ││ Suppress : warnings.simplefilter('ignore', category=IgnoredArgumentWarning) │╰──────────────────────────────────────────────────────────────────────────────────────╯
/opt/hostedtoolcache/Python/3.13.14/x64/lib/python3.13/site-packages/spotforecast2_safe/preprocessing/checking.py:916: UserWarning: Failed to set device parameter 'task_type' to 'CPU' for estimator 'CatBoostRegressor': You can't change params of fitted model.
warnings.warn(
CatBoost forecaster with real Bayesian tuning and SHAP.
Inherits the CatBoost forecaster initialisation from ForecasterRecursiveCatBoost (spotforecast2-safe) and adds the real tune() and get_global_shap_feature_importance() from ForecasterRecursiveModelFull.
The MRO ensures that tune() and SHAP methods resolve from ForecasterRecursiveModelFull, while the CatBoost-specific __init__ (estimator wiring, with the determinism flags pinned by the safe wrapper) comes from ForecasterRecursiveCatBoost.
Forwarded to parent classes (e.g., n_trials, predict_size, train_size).
{}
Examples
import numpy as npimport pandas as pdfrom catboost import CatBoostRegressorfrom spotforecast2_safe.forecaster.recursive import ForecasterRecursivefrom spotforecast2.models import ForecasterRecursiveCatBoostFullmodel = ForecasterRecursiveCatBoostFull(iteration=0, lags=3)# Swap in a tiny estimator so the example renders quickly.model.forecaster = ForecasterRecursive( estimator=CatBoostRegressor( iterations=5, depth=2, random_seed=1234, verbose=False, allow_writing_files=False, ), lags=3,)assert model.name =="catboost"assert model.iteration ==0assert model.n_trials ==10assertcallable(model.tune)assertcallable(model.get_global_shap_feature_importance)rng = np.random.default_rng(0)y = pd.Series( rng.random(30), index=pd.date_range("2023-01-01", periods=30, freq="h"),)model.fit(y=y)pred = model.forecaster.predict(steps=2)assertlen(pred) ==2print(f"name: {model.name}")print(f"iteration: {model.iteration}")print(f"n_trials: {model.n_trials}")print(f"has tune: {callable(model.tune)}")print(f"has SHAP: {callable(model.get_global_shap_feature_importance)}")print(f"forecast horizon: {len(pred)} steps")
╭─────────────────────────────── IgnoredArgumentWarning ───────────────────────────────╮│ The number of bins has been reduced from 10 to 8 due to duplicated edges caused by ││ repeated predicted values. ││││ Category : spotforecast2.exceptions.IgnoredArgumentWarning ││ Location : ││ /opt/hostedtoolcache/Python/3.13.14/x64/lib/python3.13/site-packages/spotforecast2_s ││ afe/preprocessing/_binner.py:259 ││ Suppress : warnings.simplefilter('ignore', category=IgnoredArgumentWarning) │╰──────────────────────────────────────────────────────────────────────────────────────╯
name: catboost
iteration: 0
n_trials: 10
has tune: True
has SHAP: True
forecast horizon: 2 steps
/opt/hostedtoolcache/Python/3.13.14/x64/lib/python3.13/site-packages/spotforecast2_safe/preprocessing/checking.py:916: UserWarning: Failed to set device parameter 'task_type' to 'CPU' for estimator 'CatBoostRegressor': You can't change params of fitted model.
warnings.warn(
import numpy as npimport pandas as pdfrom spotforecast2.models import ForecasterRecursiveLGBMFullrng = np.random.default_rng(0)y = pd.Series( rng.random(30), index=pd.date_range("2023-01-01", periods=30, freq="h", tz="UTC"), name="load",)# Untuned: best_params is None so an empty Series is returned.model_untuned = ForecasterRecursiveLGBMFull(iteration=0, lags=3)model_untuned.forecaster.fit(y=y)X_train_u, y_train_u = model_untuned.forecaster.create_train_X_y(y=y)model_untuned._get_training_data =lambda: (X_train_u, y_train_u)result_empty = model_untuned.get_global_shap_feature_importance()assertisinstance(result_empty, pd.Series)assertlen(result_empty) ==0print(f"Untuned result dtype: {result_empty.dtype}")
╭─────────────────────────────── IgnoredArgumentWarning ───────────────────────────────╮│ The number of bins has been reduced from 10 to 1 due to duplicated edges caused by ││ repeated predicted values. ││││ Category : spotforecast2.exceptions.IgnoredArgumentWarning ││ Location : ││ /opt/hostedtoolcache/Python/3.13.14/x64/lib/python3.13/site-packages/spotforecast2_s ││ afe/preprocessing/_binner.py:259 ││ Suppress : warnings.simplefilter('ignore', category=IgnoredArgumentWarning) │╰──────────────────────────────────────────────────────────────────────────────────────╯
Model is not tuned — returning empty Series.
Untuned result dtype: float64
import numpy as npimport pandas as pdfrom spotforecast2.models import ForecasterRecursiveLGBMFullrng = np.random.default_rng(0)y = pd.Series( rng.random(30), index=pd.date_range("2023-01-01", periods=30, freq="h", tz="UTC"), name="load",)model = ForecasterRecursiveLGBMFull(iteration=0, lags=3)model.forecaster.fit(y=y)# Set best_params and best_lags to bypass the early-return guard.model.best_params = {}model.best_lags = [1, 2, 3]# Supply pre-computed training matrices to avoid live data loading.X_train, y_train = model.forecaster.create_train_X_y(y=y)model._get_training_data =lambda: (X_train, y_train)importance = model.get_global_shap_feature_importance(frac=1.0)assertisinstance(importance, pd.Series)assertset(importance.index) == {"lag_1", "lag_2", "lag_3"}print(f"Feature importance index: {list(importance.index)}")print(importance)
╭─────────────────────────────── IgnoredArgumentWarning ───────────────────────────────╮│ The number of bins has been reduced from 10 to 1 due to duplicated edges caused by ││ repeated predicted values. ││││ Category : spotforecast2.exceptions.IgnoredArgumentWarning ││ Location : ││ /opt/hostedtoolcache/Python/3.13.14/x64/lib/python3.13/site-packages/spotforecast2_s ││ afe/preprocessing/_binner.py:259 ││ Suppress : warnings.simplefilter('ignore', category=IgnoredArgumentWarning) │╰──────────────────────────────────────────────────────────────────────────────────────╯
Loads time-series data, builds exogenous features, and runs bayesian_search_forecaster over the search space registered for self.name in SEARCH_SPACES.
After tuning the model is fitted with the best parameters and, if self.save_model_to_file is True, persisted to disk.
from spotforecast2.models import ForecasterRecursiveLGBMFullmodel = ForecasterRecursiveLGBMFull(iteration=0)assertcallable(model.tune)print(f"tune is callable: {callable(model.tune)}")print(f"n_trials={model.n_trials}, name={model.name}")