Skip to main content

A framework for forecasting time-series with multiple seasonal components

Project description

seasonality-chains

This is a framework dedicated to high-frequency forecasting of any stationary/non-stationary univariate time-series which exhibits at least one type of seasonality. It's able to forecast for years ahead with up to (currently) one hour granularity.

The main idea behind the framework and its distinction from others (e. g. statsmodels' seasonal_decompose or SARIMAX) is the ability to automatically chain different types of seasonality (daily, weekly, monthly, etc.) into one predictive model which outputs high-frequncy time-series given input of one or several terms of an arbitrary lower frequency. One can freely and flexibly stack them together in one chain as if they are building blocks of a Lego constructor. It's possible to either supply the model with high level manual predictions (e. g. give total value for a next year) or use built-in ARMA/martingale/trend predictions for next periods.

The framework is a white-box model with simple rationale: real life natural and social processes are often subject not to one, but to many types of seasonality. For example, the number of calls to an emergency service for some particular reason might simultaneously depend on time of the day, day of the week and season (winter, summer) of the year. A chain of seasonality detects and extracts all of these types of seasonality (if any are present) automatically to apply later for a prediction. Example of prediction vs actual data

Installation and use

To install the package:

pip install seasonality-chains

Or you can install from source:

git clone https://github.com/andrewargatkiny/seasonality-chains
cd seasonality-chains
pip install .

Import the library with:

from schains.tsmodels import UniformModel, SeasonalModel
from schains.chains import ChainedModels, CrossValChain

Performance in real life scenarios

This framework was in part inspired by and used in Boston Consulting Group (BSG) Gamma hackathon to solve a task of forecasting multiple (~1350) time-series of hourly frequency for a full one quarter of the year, thus yielding $90*24=2160$ data points to predict. It outperforms, both in interpretability and goodness of fit, all other ML models that were tried for achieving best predictions, including regression-based models (incl. Lasso, ElasticNet and SARIMA), ANNs, random forests and boosted trees, and also FaceBook Prophet library, specially dedicated to time-series forecasting.

Also, a model which I had built using ONLY this framework became one of the winning (top 5) in Mail.ru Group and Russian Government's ML Championship https://cups.mail.ru/ru/results/leadersofdigital2021?period=past&roundId=616. The task was to predict prices and sales volumes of 39 categories of consumer goods for 3 months ahead on a daily basis for 85 distinct russian regions.

Examples

Basic usage examples:

# If your time-series exhibits both weekly and month-of-the-year types
# of seasonality:
models = [SeasonalModel('m', use_input_freq='y'),
    SeasonalModel('d', use_input_freq='w')]
# If it's just month-of-the-year (no weekly oscillations):
models = [SeasonalModel('m', use_input_freq='y'), UniformModel('d')]
# (Each predicted day within a single month will have the same value)

# If it exhibits day-of-the-year seasonality (resulting in 365 seasonal
# indices):
models = [SeasonalModel('d', use_input_freq='y')]

# If value of ts' term depends both on the day of the week and the time
# (season) of the year (for example, 4th Monday of the year always has
# value greater than 11th):
models = [TimeWeekOfYear('d', excl_holidays=True, before_hol=5, after_hol=2)]
# Predefined holidays, 5 days before and 2 days after are modeled just
# by day-of-the-year seasonality, disregarding weekly oscillations.

# If there's no seasonality at all (or you want to model only 
# arma/trend/martingale terms):
models = [UniformModel('d')]
# If you want to predict by a median:
models = [MedianModel('d')]

# Assuming ts is your time-series (pd.Series) with daily frequency
# and its index is a PeriodIndex.
chain = CrossValChain(
    chain_of_models=models, 
    train_ts=ts, # time-series for training seasonal weights of all models
    input_ts=ts.resample('m'), # time-series with frequency >= frequncy of
    # first model in the chain. Used for cross-val and out of sample 
    # predictions.
    step=pd.pd.DateOffset(months=1), # should be equal to input_ts.freq
    train_period=0, # number of past step periods to calculate seasonality
    # for each stage of cross-val or out-of-sample period. When equal to 
    # 0, uses all prior data.
    ar_period=3, # number of past step periods to get next arma/trend/
    # martingale prediction
    trend=True, # use if time-series has a linear trend
    deseason = True, # you can set to false if seasonality is negligible
    # or 'ar_period' is a multiple of lowest frequency used (e.g. 12 
    # months for [SeasonalModel('m', use_input_freq='y'), UniformModel('d')].
    calc_func=SeasonalModel.get_median_weights,
    stype='additive' # 'multiplicative' by default in all models
)
# Cross-validation (assuming ts' index range is at least from 2019-03 and till 
# 2020-12):
chain.predict(pd.Timestamp('2020-01'), pd.Timestamp('2021-01'))
mae = chain.prediction_mae(ground_truth=ts)
print(chain.mae) # or print(chain.metrics)
# Forecast out-of-sample for 9 months ahead:
prediction = chain.predict(pd.Timestamp('2021-01'), pd.Timestamp('2021-10'))
print(prediction) # or print(chain.prediction)

More detailed examples of current version's features (basic and advanced) are coming later. As of now, you can learn about them with built-on python help() function passing any model or chain name to it as an argument.

Examples of the use of the previous version, experience with the contest along with optimal solution, and its merits and perfomance in a real life problem are described in an article structured as a Jupyter Notebook and availible at Contest Solution & Real Life Use. Give it a read!

Versions history

0.2.0

New features in chains:

  • Trend – option to use trend based on simple linear regression
  • Deseasoning – option to deseason low-granularity time-series before applying ARMA/trend prediction
  • Prediction period – an option to choose a number of steps which models predicts before next step of Walk-Forward cross-validation
  • Full training - an option to learn seasonality from all availible training data (even during cross-validation).
  • Don't retrain - option to derive seasonality weights of all models in a chain only once for performance reasons. Use with full training.

New features in tsmodels:

  • Each time-series now can be classified as one of two datatypes – 'flow' (values can be summed or integrated over time, like volumes or calls/customers per hour) and 'stock', which are basicly point-in-time and are not integrable/divisible (e.g. prices).
  • use_input_freq parameter. It determines, seasonal weights of which frequency will be used in predict method of SeasonalModel, overriding frequency of input time-series.
  • TimeWeekOfYear model. It simultaneously takes into accont two types of seasonality: a moment during the week and its approximate location within the year timespan. It also considers regular and rolling (e.g. Easter) holidays and dates around them, and predicts them solely by day-of-the-year seasonality.
  • MedianModel – predicts input time-series by a median of values supplies during training.

Current limitation: holidays list is hardcoded into TimeWeekOfYear model and it's nesessary to edit source file in order to alter it.

0.1.0

The framework uses 2 types of models which represent building blocks for the chains of seasonality:

  • UniformModel(output frequency) – takes input time-series and uniformly upsamples it into output frequency;
  • SeasonalModel(output frequency) – can be trained on past high-frequency data to estimate and store seasonal weights (indices) for compatible lower frequnces. It takes input time-series, converts to output frequency using UniformModel and, if its original frequency matches one with availible indices, applies them to the series to get final prediction.

Seasonal model is equipped with three functions which can be used to calculate seasonal indices:

  • Mean
  • Median
  • Quantile (percentile) of an arbitrary order q The functions calculate generalized values of seasonal periods based on their respective statistics and compare them with overal mean of training time-series to produce either additive or multiplicative type indices. An output of a model can be an input of another model as long as its frequency is lower or equal than second model's output frequency.

The framework has two built-in types of chains:

  • base ChainOfModels which offers flexibility in construction and selection of data for training the models and forming predictions on;
  • CrossValChain which trains seasonalal models and bases predictions on recent data of user-specified time-windows (train_perdiod and ar_period). It employs simple MA model to predict next high-level values of input, which is conceptually close to ARMA or martingale random processes models, depending on number of considered past lags. Given a past time-series of sufficient length, it can perform a one-step walk-forward time-series validation, hence the name CrossValChain.

In-depth examples of the use of these types of chains are in the Jupyter Notebook file.

This library is a work in progress. Current limitations:

  • When in multiplicative mode, works correctly only with nonnegative input time-series.
  • ARMA calculation is a simple moving average of ar_period preceeding periods (no prior deseasoning supported). If ar_period=1, it’s a martingale model.
  • No trend models, only stationary ARMA/martingale based predictions

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

seasonality-chains-0.2.0.tar.gz (21.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

seasonality_chains-0.2.0-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

Details for the file seasonality-chains-0.2.0.tar.gz.

File metadata

  • Download URL: seasonality-chains-0.2.0.tar.gz
  • Upload date:
  • Size: 21.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.2 CPython/3.9.5

File hashes

Hashes for seasonality-chains-0.2.0.tar.gz
Algorithm Hash digest
SHA256 21ad7aa3d2f0868bcc3918314e48f746df4baeac2506c987fde8e75a5eba6837
MD5 22b79fa45f130bdf14494952d903b05b
BLAKE2b-256 4762d73aa0a8c811ab2af3b002f80b81f1523c0d88e8f8f137445d4375346acd

See more details on using hashes here.

File details

Details for the file seasonality_chains-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: seasonality_chains-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 18.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.2 CPython/3.9.5

File hashes

Hashes for seasonality_chains-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cb4ca8c0f01f1d859a3b1dd32df73477803803c4d93130bd270aa810237814ae
MD5 5f61d551af17994a632efd47307851bf
BLAKE2b-256 88b45447251f44a340ffda3f051a2398d9590860c3d603b6d21b2f0882932bd7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page