Model training, evaluation and selection for multiple time series
Prerequesites This Guide assumes basic familiarity with StatsForecast. For a minimal example visit the Quick StartFollow this article for a step to step guide on building a production-ready forecasting pipeline for multiple time series. During this guide you will gain familiary with the core
StatsForecast
class
and some relevant methods like StatsForecast.plot
,
StatsForecast.forecast
and StatsForecast.cross_validation.
We will use a classical benchmarking dataset from the M4 competition.
The dataset includes time series from different domains like finance,
economy and sales. In this example, we will use a subset of the Hourly
dataset.
We will model each time series individually. Forecasting at this level
is also known as local forecasting. Therefore, you will train a series
of models for every unique series and then select the best one.
StatsForecast focuses on speed, simplicity, and scalability, which makes
it ideal for this task.
Outline:
Not Covered in this guide
- Forecasting at scale using clusters on the cloud.
- Forecast the M5 Dataset in 5min using Ray clusters.
- Forecast the M5 Dataset in 5min using Spark clusters.
- Learn how to predict 1M series in less than 30min.
- Training models on Multiple Seasonalities.
- Learn to use multiple seasonality in this Electricity Load forecasting tutorial.
- Using external regressors or exogenous variables
- Follow this tutorial to include exogenous variables like weather or holidays or static variables like category or family.
- Comparing StatsForecast with other popular libraries.
- You can reproduce our benchmarks here.
.csv
.
The input to StatsForecast is always a data frame in long
format with
three columns: unique_id
, ds
and y
:
unique_id
(string, int or category) represents an identifier
for the series.
ds
(datestamp or int) column should be either an integer
indexing time or a datestampe ideally like YYYY-MM-DD for a date or
YYYY-MM-DD HH:MM:SS for a timestamp.
y
(numeric) represents the measurement we wish to forecast.
unique_id | ds | y |
---|---|---|
str | i64 | f64 |
”H1” | 1 | 605.0 |
”H1” | 2 | 586.0 |
”H1” | 3 | 586.0 |
”H1” | 4 | 559.0 |
”H1” | 5 | 511.0 |
Note Processing time is dependent on the available computing resources. Running this example with the complete dataset takes around 10 minutes in a c5d.24xlarge (96 cores) instance from AWS.
plot
method from the
StatsForecast
class. This method prints 8 random series from the dataset and is useful
for basic EDA.
Note TheStatsForecast.plot
method uses matplotlib as a default engine. You can change to plotly by settingengine="plotly"
.
AutoARIMA
:
Automatically selects the best ARIMA (AutoRegressive Integrated
Moving Average) model using an information criterion. Ref:
AutoARIMA
.
HoltWinters
:
triple exponential smoothing, Holt-Winters’ method is an extension
of exponential smoothing for series that contain both trend and
seasonality. Ref:
HoltWinters
SeasonalNaive
:
Memory Efficient Seasonal Naive predictions. Ref:
SeasonalNaive
HistoricAverage
:
arthimetic mean. Ref:
HistoricAverage
.
DynamicOptimizedTheta
:
The theta family of models has been shown to perform well in various
datasets such as M3. Models the deseasonalized time series. Ref:
DynamicOptimizedTheta
.
season_length
argument
is sometimes tricky. This article on Seasonal
periods) by the
master, Rob Hyndmann, can be useful.
StatsForecast
object with the following parameters:
models
: a list of models. Select the models you want from
models and import them.
freq
: a string indicating the frequency of the data. (See panda’s
available
frequencies.)
This is also available with Polars.
n_jobs
: n_jobs: int, number of jobs used in the parallel
processing, use -1 for all cores.
fallback_model
: a model to be used if a model fails.
Note StatsForecast achieves its blazing speed using JIT compiling through Numba. The first time you call the statsforecast class, the fit method should take around 5 seconds. The second time -once Numba compiled your settings- it should take less than 0.2s.The
forecast
method takes two arguments: forecasts next h
(horizon)
and level
.
h
(int): represents the forecast h steps into the future. In this
case, 12 months ahead.
level
(list of floats): this optional parameter is used for
probabilistic forecasting. Set the level
(or confidence
percentile) of your prediction interval. For example, level=[90]
means that the model expects the real value to be inside that
interval 90% of the times.
Note Theforecast
method is compatible with distributed clusters, so it does not store any model parameters. If you want to store parameters for every model you can use thefit
andpredict
methods. However, those methods are not defined for distrubed engines like Spark, Ray or Dask.
unique_id | ds | HoltWinters | HoltWinters-lo-90 | HoltWinters-hi-90 | CrostonClassic | CrostonClassic-lo-90 | CrostonClassic-hi-90 | SeasonalNaive | SeasonalNaive-lo-90 | SeasonalNaive-hi-90 | HistoricAverage | HistoricAverage-lo-90 | HistoricAverage-hi-90 | DynamicOptimizedTheta | DynamicOptimizedTheta-lo-90 | DynamicOptimizedTheta-hi-90 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
str | i64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 | f64 |
”H1” | 749 | 829.0 | 422.549268 | 1235.450732 | 829.0 | 422.549268 | 1235.450732 | 635.0 | 566.036734 | 703.963266 | 660.982143 | 398.037761 | 923.926524 | 592.701851 | 577.67728 | 611.652639 |
”H1” | 750 | 807.0 | 400.549268 | 1213.450732 | 807.0 | 400.549268 | 1213.450732 | 572.0 | 503.036734 | 640.963266 | 660.982143 | 398.037761 | 923.926524 | 525.589116 | 505.449755 | 546.621805 |
”H1” | 751 | 785.0 | 378.549268 | 1191.450732 | 785.0 | 378.549268 | 1191.450732 | 532.0 | 463.036734 | 600.963266 | 660.982143 | 398.037761 | 923.926524 | 489.251814 | 462.072871 | 512.424116 |
”H1” | 752 | 756.0 | 349.549268 | 1162.450732 | 756.0 | 349.549268 | 1162.450732 | 493.0 | 424.036734 | 561.963266 | 660.982143 | 398.037761 | 923.926524 | 456.195032 | 430.554302 | 478.260963 |
”H1” | 753 | 719.0 | 312.549268 | 1125.450732 | 719.0 | 312.549268 | 1125.450732 | 477.0 | 408.036734 | 545.963266 | 660.982143 | 398.037761 | 923.926524 | 436.290514 | 411.051232 | 461.815932 |
StatsForecast.plot
method.
StatsForecast.plot
allows for further customization. For example,
plot the results of the different models and unique ids.
Tip
Setting n_windows=1
mirrors a traditional train-test split with our
historical data serving as the training set and the last 48 hours
serving as the testing set.
The
cross_validation
method from the
StatsForecast
class takes the following arguments.
df
: training data frame
h
(int): represents h steps into the future that are being
forecasted. In this case, 24 hours ahead.
step_size
(int): step size between each window. In other words:
how often do you want to run the forecasting processes.
n_windows
(int): number of windows used for cross validation. In
other words: what number of forecasting processes in the past do you
want to evaluate.
cv_df
object is a new data frame that includes the following
columns:
unique_id
: series identifier
ds
: datestamp or temporal index
cutoff
: the last datestamp or temporal index for the n_windows.
If n_windows=1
, then one unique cuttoff value, if n_windows=2
then two unique cutoff values.
y
: true value
"model"
: columns with the model’s name and fitted value.
unique_id | ds | cutoff | y | HoltWinters | CrostonClassic | SeasonalNaive | HistoricAverage | DynamicOptimizedTheta |
---|---|---|---|---|---|---|---|---|
str | i64 | i64 | f64 | f64 | f64 | f64 | f64 | f64 |
”H1” | 701 | 700 | 619.0 | 847.0 | 742.668748 | 691.0 | 661.675 | 612.767504 |
”H1” | 702 | 700 | 565.0 | 820.0 | 742.668748 | 618.0 | 661.675 | 536.846278 |
”H1” | 703 | 700 | 532.0 | 790.0 | 742.668748 | 563.0 | 661.675 | 497.824286 |
”H1” | 704 | 700 | 495.0 | 784.0 | 742.668748 | 529.0 | 661.675 | 464.723219 |
”H1” | 705 | 700 | 481.0 | 752.0 | 742.668748 | 504.0 | 661.675 | 440.972336 |
utilsforecast.losses
. Then
define a utility function that takes a cross-validation data frame as a
metric and returns an evaluation data frame with the average of the
error metric for every unique id and fitted model and all cutoffs.
Warning You can also use Mean Average Percentage Error (MAPE), however for granular forecasts, MAPE values are extremely hard to judge and not useful to assess forecasting quality.Create the data frame with the results of the evaluation of your cross-validation data frame using a Mean Squared Error metric.
unique_id | HoltWinters | CrostonClassic | SeasonalNaive | HistoricAverage | DynamicOptimizedTheta | best_model |
---|---|---|---|---|---|---|
str | f64 | f64 | f64 | f64 | f64 | str |
”H1” | 44888.020833 | 28038.733985 | 1422.666667 | 20927.664488 | 1296.333977 | ”DynamicOptimizedTheta" |
"H10” | 2812.916667 | 1483.483839 | 96.895833 | 1980.367543 | 379.621134 | ”SeasonalNaive" |
"H100” | 121625.375 | 91945.139237 | 12019.0 | 78491.191439 | 21699.649325 | ”SeasonalNaive" |
"H101” | 28453.395833 | 16183.63434 | 10944.458333 | 18208.4098 | 63698.077266 | ”SeasonalNaive" |
"H102” | 232924.854167 | 132655.309136 | 12699.895833 | 309110.475212 | 31393.535274 | ”SeasonalNaive” |
best_model | count |
---|---|
str | u32 |
”DynamicOptimizedTheta” | 4 |
”SeasonalNaive” | 6 |
unique_id | ds | best_model | best_model-lo-90 | best_model-hi-90 |
---|---|---|---|---|
str | i64 | f64 | f64 | f64 |
”H1” | 749 | 592.701851 | 577.67728 | 611.652639 |
”H1” | 750 | 525.589116 | 505.449755 | 546.621805 |
”H1” | 751 | 489.251814 | 462.072871 | 512.424116 |
”H1” | 752 | 456.195032 | 430.554302 | 478.260963 |
”H1” | 753 | 436.290514 | 411.051232 | 461.815932 |