models.forecaster_recursive_catboost_full

models.forecaster_recursive_catboost_full

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 np
import pandas as pd
from catboost import CatBoostRegressor

from spotforecast2_safe.forecaster.recursive import ForecasterRecursive
from spotforecast2.models import ForecasterRecursiveCatBoostFull

model = 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 == 10

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)
assert len(pred) == 2
print(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)          
╰──────────────────────────────────────────────────────────────────────────────────────╯
name: catboost
n_trials: 10
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(

Classes

Name Description
ForecasterRecursiveCatBoostFull CatBoost forecaster with real Bayesian tuning and SHAP.

ForecasterRecursiveCatBoostFull

models.forecaster_recursive_catboost_full.ForecasterRecursiveCatBoostFull(
    iteration,
    lags=12,
    **kwargs,
)

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.

Parameters

Name Type Description Default
iteration int Training iteration index (0-based). required
lags int Number of lag features to use. 12
**kwargs Any Forwarded to parent classes (e.g., n_trials, predict_size, train_size). {}

Examples

import numpy as np
import pandas as pd
from catboost import CatBoostRegressor

from spotforecast2_safe.forecaster.recursive import ForecasterRecursive
from spotforecast2.models import ForecasterRecursiveCatBoostFull

model = 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 == 0
assert model.n_trials == 10
assert callable(model.tune)
assert callable(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)
assert len(pred) == 2
print(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(

Methods

Name Description
get_global_shap_feature_importance Return global SHAP-based feature importances.
tune Tune the forecaster via Bayesian search (Optuna).
get_global_shap_feature_importance
models.forecaster_recursive_catboost_full.ForecasterRecursiveCatBoostFull.get_global_shap_feature_importance(
    frac=0.1,
)

Return global SHAP-based feature importances.

Uses shap.TreeExplainer on the underlying estimator to compute mean absolute SHAP values across a random sample of the training data.

Parameters
Name Type Description Default
frac float Fraction of training data to sample (0 < frac <= 1). 0.1
Returns
Name Type Description
pd.Series pd.Series: Feature importances sorted descending. Empty
pd.Series if the model has not been tuned.
Raises
Name Type Description
ValueError If the forecaster has not been initialized.
Examples
import numpy as np
import pandas as pd
from spotforecast2.models import ForecasterRecursiveLGBMFull

rng = 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()
assert isinstance(result_empty, pd.Series)
assert len(result_empty) == 0
print(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 np
import pandas as pd
from spotforecast2.models import ForecasterRecursiveLGBMFull

rng = 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)
assert isinstance(importance, pd.Series)
assert set(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)          
╰──────────────────────────────────────────────────────────────────────────────────────╯
Feature importance index: ['lag_1', 'lag_2', 'lag_3']
lag_1    0.0
lag_2    0.0
lag_3    0.0
dtype: float64
tune
models.forecaster_recursive_catboost_full.ForecasterRecursiveCatBoostFull.tune()

Tune the forecaster via Bayesian search (Optuna).

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.

Raises
Name Type Description
KeyError If self.name is not in SEARCH_SPACES.
Examples
from spotforecast2.models import ForecasterRecursiveLGBMFull

model = ForecasterRecursiveLGBMFull(iteration=0)
assert callable(model.tune)
print(f"tune is callable: {callable(model.tune)}")
print(f"n_trials={model.n_trials}, name={model.name}")
tune is callable: True
n_trials=10, name=lgbm