Forecasts multiple time series simultaneously using a global model with ForecasterRecursiveMultiSeries or ForecasterDirectMultiVariate. Covers data formats, encoding, per-series transformers, and multi-series backtesting. Use when the user has two or more related time series.
ForecasterRecursiveMultiSeries accepts three input formats:
Wide DataFrame — columns are series, index is datetime:
# series_1 series_2 series_3
# 2020-01-01 1.0 2.5 3.1
# 2020-01-02 1.2 2.3 3.4
Dictionary — :
{series_id: pd.Series}{'series_1': pd.Series([1.0, 1.2, ...]), 'series_2': pd.Series([2.5, 2.3, ...])}
Note: Long-format DataFrames are not directly accepted. Use
reshape_series_long_to_dict()to convert long format to a dictionary first (see Data Reshaping Utilities below).
import pandas as pd
from lightgbm import LGBMRegressor
from skforecast.recursive import ForecasterRecursiveMultiSeries
from skforecast.model_selection import backtesting_forecaster_multiseries, TimeSeriesFold
# 1. Load data as wide DataFrame (columns = series)
series = pd.read_csv('data.csv', index_col='date', parse_dates=True)
series = series.asfreq('D')
# 2. Create forecaster
forecaster = ForecasterRecursiveMultiSeries(
estimator=LGBMRegressor(n_estimators=200, random_state=123),
lags=24,
encoding='ordinal', # 'ordinal', 'ordinal_category', 'onehot', or None
transformer_series=None, # Apply same transformer to all series
# Per-series options (dict):
# transformer_series={'series_1': StandardScaler(), 'series_2': MinMaxScaler()},
# weight_func={'series_1': custom_weights_fn, '_default': None},
# differentiation={'series_1': 1, 'series_2': None},
differentiation=None,
dropna_from_series=False, # Set True if individual series may have NaN
)
# 3. Train
forecaster.fit(series=series)
# 4. Predict all series
predictions = forecaster.predict(steps=10)
# 5. Predict specific series only
predictions = forecaster.predict(steps=10, levels=['series_1', 'series_2'])
# 6. Backtesting (multi-series)
cv = TimeSeriesFold(
steps=10,
initial_train_size=len(series) - 100,
refit=False,
)
metric, predictions_bt = backtesting_forecaster_multiseries(
forecaster=forecaster,
series=series,
cv=cv,
metric='mean_absolute_error',
levels=None, # Evaluate all series
)
print(metric) # Shows per-series and aggregated metrics
# Exog can also be wide DataFrame, long DataFrame, or dict
forecaster.fit(series=series, exog=exog_df)
predictions = forecaster.predict(steps=10, exog=exog_test)
from skforecast.direct import ForecasterDirectMultiVariate
# Predicts ONE target series using lags from ALL series as features
# Note: transformer_series defaults to StandardScaler() (unlike other forecasters)
forecaster = ForecasterDirectMultiVariate(
level='target_series', # Name of the series to predict
steps=10,
estimator=LGBMRegressor(n_estimators=100, random_state=123),
lags=24, # Or dict: {'series_a': 12, 'series_b': 24}
transformer_series=StandardScaler(), # Default — set None to disable scaling
)
forecaster.fit(series=series_df)
predictions = forecaster.predict()
from skforecast.preprocessing import (
reshape_series_wide_to_long,
reshape_series_long_to_dict,
reshape_exog_long_to_dict,
reshape_series_exog_dict_to_long,
)
# Wide → Long
series_long = reshape_series_wide_to_long(series_wide)
# Long → Dict (freq is required)
series_dict = reshape_series_long_to_dict(series_long, freq='D')
exog_dict = reshape_exog_long_to_dict(exog_long, freq='D')
dropna_from_series=True.encoding='ordinal_category' with regressors that natively handle categoricals (LightGBM, CatBoost).levels parameter: By default predict() forecasts all series. Use levels to limit predictions.transformer_series defaults to StandardScaler(), unlike other forecasters that default to None. Set transformer_series=None explicitly if you don't want automatic scaling.