Tuning Prophetverse with sktime

This guide explains how to optimize Prophetverse model hyperparameters using sktime’s tuning classes (e.g., GridSearchCV).

Overview

Prophetverse is compatible with sktime’s tuning framework. You can define a parameter grid for components (such as trend and seasonality) and then use cross-validation tools (e.g., GridSearchCV) to search for the best parameters.

Example: Using GridSearchCV with Prophetverse

  1. Import necessary modules and load your dataset.
  2. Define the hyperparameter grid for components (e.g., changepoint_interval and changepoint_prior_scale in the trend).
  3. Create a Prophetverse instance with initial settings.
  4. Wrap the model with sktime’s GridSearchCV and run the tuning process.

Loading the data

import pandas as pd
from sktime.forecasting.model_selection import ForecastingGridSearchCV
from prophetverse.sktime import Prophetverse
from prophetverse.effects.trend import PiecewiseLinearTrend
from prophetverse.effects.fourier import LinearFourierSeasonality
from prophetverse.engine import MAPInferenceEngine
from prophetverse.utils import no_input_columns

# Load example dataset (replace with your own data as needed)
from prophetverse.datasets.loaders import load_peyton_manning

y = load_peyton_manning()
y.head()
/opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
y
ds
2007-12-10 9.590761
2007-12-11 8.519590
2007-12-12 8.183677
2007-12-13 8.072467
2007-12-14 7.893572

Setting the model

We create our model instance, before passing it to tuning.

# Create the initial Prophetverse model.
model = Prophetverse(
    trend=PiecewiseLinearTrend(
        changepoint_interval=500,
        changepoint_prior_scale=0.00001,
        changepoint_range=-250,
    ),
    exogenous_effects=[
        (
            "seasonality",
            LinearFourierSeasonality(
                freq="D",
                sp_list=[7, 365.25],
                fourier_terms_list=[3, 10],
                prior_scale=0.1,
                effect_mode="multiplicative",
            ),
            no_input_columns,
        ),
    ],
    inference_engine=MAPInferenceEngine(),
)
model
Prophetverse(exogenous_effects=[('seasonality',
                                 LinearFourierSeasonality(effect_mode='multiplicative',
                                                          fourier_terms_list=[3,
                                                                              10],
                                                          freq='D',
                                                          prior_scale=0.1,
                                                          sp_list=[7, 365.25]),
                                 '^$')],
             inference_engine=MAPInferenceEngine(),
             trend=PiecewiseLinearTrend(changepoint_interval=500,
                                        changepoint_prior_scale=1e-05,
                                        changepoint_range=-250))
Please rerun this cell to show the HTML repr or trust the notebook.

Define the searcher

In sktime, the tuner is also an estimator/forecaster, so we can use the same interface as for any other sktime forecaster. We can use GridSearchCV to search for the best parameters in a given parameter grid.

# Set up cv strategy
from sktime.split import ExpandingWindowSplitter

cv = ExpandingWindowSplitter(fh=[1, 2, 3], step_length=1000, initial_window=1000)

param_grid = {
    "trend__changepoint_interval": [300, 700],
    "trend__changepoint_prior_scale": [0.0001, 0.00001],
    "seasonality__prior_scale": [0.1],
}


# Set up GridSearchCV with 3-fold cross-validation.
grid_search = ForecastingGridSearchCV(
                model,
                param_grid=param_grid,
                cv=cv
            )
grid_search
ForecastingGridSearchCV(cv=ExpandingWindowSplitter(fh=[1, 2, 3],
                                                   initial_window=1000,
                                                   step_length=1000),
                        forecaster=Prophetverse(exogenous_effects=[('seasonality',
                                                                    LinearFourierSeasonality(effect_mode='multiplicative',
                                                                                             fourier_terms_list=[3,
                                                                                                                 10],
                                                                                             freq='D',
                                                                                             prior_scale=0.1,
                                                                                             sp_list=[7,
                                                                                                      365.25]),
                                                                    '^$')],
                                                inference_engine=MAPInferenceEngine(),
                                                trend=PiecewiseLinearTrend(changepoint_interval=500,
                                                                           changepoint_prior_scale=1e-05,
                                                                           changepoint_range=-250)),
                        param_grid={'seasonality__prior_scale': [0.1],
                                    'trend__changepoint_interval': [300, 700],
                                    'trend__changepoint_prior_scale': [0.0001,
                                                                       1e-05]})
Please rerun this cell to show the HTML repr or trust the notebook.

Now, we can call fit.

# Run the grid search.
grid_search.fit(y=y, X=None)

# Display the best parameters found.
print("Best parameters:", grid_search.best_params_)
/home/runner/work/prophetverse/prophetverse/src/prophetverse/sktime/univariate.py:244: UserWarning: No columns match the regex ^$
  self._fit_effects(X, y)
/home/runner/work/prophetverse/prophetverse/src/prophetverse/sktime/univariate.py:244: UserWarning: No columns match the regex ^$
  self._fit_effects(X, y)
/home/runner/work/prophetverse/prophetverse/src/prophetverse/sktime/univariate.py:244: UserWarning: No columns match the regex ^$
  self._fit_effects(X, y)
/home/runner/work/prophetverse/prophetverse/src/prophetverse/sktime/univariate.py:244: UserWarning: No columns match the regex ^$
  self._fit_effects(X, y)
/home/runner/work/prophetverse/prophetverse/src/prophetverse/sktime/univariate.py:244: UserWarning: No columns match the regex ^$
  self._fit_effects(X, y)
/home/runner/work/prophetverse/prophetverse/src/prophetverse/sktime/univariate.py:244: UserWarning: No columns match the regex ^$
  self._fit_effects(X, y)
/home/runner/work/prophetverse/prophetverse/src/prophetverse/sktime/univariate.py:244: UserWarning: No columns match the regex ^$
  self._fit_effects(X, y)
/home/runner/work/prophetverse/prophetverse/src/prophetverse/sktime/univariate.py:244: UserWarning: No columns match the regex ^$
  self._fit_effects(X, y)
Best parameters: {'seasonality__prior_scale': 0.1, 'trend__changepoint_interval': 700, 'trend__changepoint_prior_scale': 1e-05}

We can also see the performance of each parameter combination:

grid_search.cv_results_
mean_test_MeanAbsolutePercentageError mean_fit_time mean_pred_time params rank_test_MeanAbsolutePercentageError
0 0.053894 13.491835 0.918617 {'seasonality__prior_scale': 0.1, 'trend__chan... 4.0
1 0.049266 15.174710 0.676995 {'seasonality__prior_scale': 0.1, 'trend__chan... 3.0
2 0.036171 15.191038 0.953519 {'seasonality__prior_scale': 0.1, 'trend__chan... 2.0
3 0.033468 16.871816 0.638110 {'seasonality__prior_scale': 0.1, 'trend__chan... 1.0

Optionally, extract the best model from the grid search results.

best_model = grid_search.best_forecaster_
best_model
Prophetverse(exogenous_effects=[('seasonality',
                                 LinearFourierSeasonality(effect_mode='multiplicative',
                                                          fourier_terms_list=[3,
                                                                              10],
                                                          freq='D',
                                                          prior_scale=0.1,
                                                          sp_list=[7, 365.25]),
                                 '^$')],
             inference_engine=MAPInferenceEngine(),
             trend=PiecewiseLinearTrend(changepoint_interval=700,
                                        changepoint_prior_scale=1e-05,
                                        changepoint_range=-250))
Please rerun this cell to show the HTML repr or trust the notebook.