Hierarchical Forecasting Model

Hierarchical Forecasting Model (HFModel) is defined by pyhts.HFModel

HFModel API

class pyhts.HFModel(hierarchy, base_forecasters, hf_method='comb', comb_method='ols', weights=None, immutable_set=None)

Model for hierarchical forecasting.

__init__(hierarchy, base_forecasters, hf_method='comb', comb_method='ols', weights=None, immutable_set=None)

Define a hierarchical forecasting model.

Parameters
  • hierarchy (Hierarchy) – hierarchical structure of the data.

  • base_forecasters (Union[List[BaseForecaster], str]) – base forecasting method, list of custom forecaster objects or str arima implemented by statsforecast.

  • hf_method (str) – method for hierarchical forecasting, comb is only supported for now, which represents optimal combination method.

  • comb_method (str) – method for forecast reconciliation, ols, wls or mint.

  • weights (Union[str, ndarray, None]) – weighting matrix used in wls and mint, “structural” or custom symmetric matrix for wls, “shrinkage”, “sample”, “variance” for mint.

  • immutable_set (Optional[Iterable[int]]) – the subset of time series to be unchanged during reconciliation

fit(ts, xreg=None, **kwargs)

Fit a base forecast model and calculate the reconciliation matrix used for reconciliation.

Parameters
  • ts (DataFrame) – T * m, each column represents one bottom-level time series. The order of series should be same as the order when defining hierarchy.

  • xreg (Optional[array]) – explanatory variables with shape (n, T, k), where n is number of time series, T is history length, and k is dimension of explanatory variables.

  • kwargs – parameters passed to base_forecasters.

Returns

fitted HFModel

predict(horizon=1, xreg=None, **kwargs)

Generate horizon-step-ahead reconciled base forecasts of the bottom level.

Parameters
  • horizon (int) – forecast horizon

  • xreg – explanatory variables with shape (n, h, k), where n is number of time series, h is forecast horizon, and k is dimension of explanatory variables.

  • kwargs – other parameters passed to base forecasters.

Return type

array

Returns

coherent forecasts of the bottom level.

Examples

load Tourism dataset

>>> from pyhts import load_tourism
>>> from pyhts import Hierarchy
>>> dataset = load_tourism()
>>> dataset.columns
Index(['AAA', 'AAB', 'ABA', 'ABB', 'ACA', 'ADA', 'ADB', 'ADC', 'ADD', 'AEA',
       'AEB', 'AEC', 'AED', 'AFA', 'BAA', 'BAB', 'BAC', 'BBA', 'BCA', 'BCB',
       'BCC', 'BDA', 'BDB', 'BDC', 'BDD', 'BDE', 'BDF', 'BEA', 'BEB', 'BEC',
       'BED', 'BEE', 'BEF', 'BEG', 'BEH', 'CAA', 'CAB', 'CAC', 'CBA', 'CBB',
       'CBC', 'CBD', 'CCA', 'CCB', 'CCC', 'CDA', 'CDB', 'DAA', 'DAB', 'DAC',
       'DBA', 'DBB', 'DBC', 'DCA', 'DCB', 'DCC', 'DCD', 'DDA', 'DDB', 'EAA',
       'EAB', 'EAC', 'EBA', 'ECA', 'FAA', 'FBA', 'FBB', 'FCA', 'FCB', 'GAA',
       'GAB', 'GAC', 'GBA', 'GBB', 'GBC', 'GBD'],
      dtype='object')
>>> train = dataset.iloc[:-12,]
>>> test = dataset.iloc[-12:,]
>>> ht = Hierarchy.from_names(dataset.columns, [1, 1, 1], period=12)

Define HFModel

Then, define the hierarchical forecasting model.

ols proposed by Hyndman et al.(2011) 1

model = HFModel(ht, base_forecasters = "arima", hf_method="comb", comb_method="ols")

WLS_Structural, also known as \(WLS_s\) in Wickramasuriya et al.(2019) 2

model = HFModel(ht, "arima", "comb", "wls", weights="structural")

Mint_variance, also known as \(WLS_v\) in Wickramasuriya et al.(2019) 2

model = HFModel(ht, "arima", "comb", "mint", weights="variance")

Mint_sample, also known as Mint_sample in Wickramasuriya et al.(2019) 2

model = HFModel(ht, "arima", "comb", "mint", weights="sample")

Mint_shrinakge, also known as Mint_shrinkage in Wickramasuriya et al.(2019) 2

>>> model = HFModel(ht, "arima", "comb", "mint", weights="shrinkage")

customize base forecasters

TODO: update docs

To generate base forecasts, you can use arima, which are implemented by statsforecast, or you can define your own base forecasters using whatever forecasting methods you want, machine learning or deeplearning methods.

  • fit(ts, xreg, **kwargs) is needed for the base forecaster, which is used to fit base forecasting model and generate insample forecasts fitted, which is necessary when comb_method is mint.

  • forecast(h, xreg, **kwargs) is needed for the base forecaster, which is used to generate base forecasts.

As an example, here is the implementation of AutoArimaBaseForecaster

class AutoArimaForecaster(BaseForecaster):
"""autoarima forecaster, adapted from statsforecast.arima.auto_arima_f

"""

def __init__(self, period: int = 1):
    super().__init__()
    self.period = period
    self.hist = None
    self.model = None

def fit(self, hist: np.ndarray, xreg=None, **kwargs):
    """fit the AutoArimaForecaster

    :param hist: observations
    :param xreg: covariates of arima model
    :param kwargs: other parameters passed to  `statsforecast.arima.auto_arima_f`
    :return: self
    """
    self.hist = hist
    self.model = auto_arima_f(hist, period=self.period, xreg=xreg, **kwargs)
    self.fitted = True
    return self

def forecast(self, h: int, xreg=None, **kwargs) -> np.ndarray:
    """forecast

    :param h: forecast horizons
    :param xreg: covariates
    :param kwargs: other parameters passed to `statsforecast.arima.forecast_arima`
    :return:
    """
    return forecast_arima(self.model, h, xreg=xreg, **kwargs)['mean']

Assuming you have trained a global XGBoost model, you can wrap the xgboost model and pass it to base_forecasters.

class XGBoostWrapper:

    def __init__(self):
        self._model = trained_xgbmodel
        self.fitted = None

    def fit(self, hist, x_reg, **kwargs):
        self.fitted = self._model.predict(x_reg)

    def forecast(self, h: int, x_reg, **kwargs):
        return self._model.predict(x_reg)

xgb_model = HFModel(ht, base_forecasters=[XGBoostWrapper], hf_method='comb', comb_method='ols')

Fit HFModel

fit() will fit the base forecasters and reconcile the incoherent base forecasts to coherent forecasts.

Here is an example that fit a mint shrinkage model with AAA type ets base forecasters.

>>> ols_model = HFModel(ht, "ets", "comb", "mint", weights="shrinkage")
>>> ols_model.fit(train, model ='AAA')

the parameter model will be passed to ETSBaseForecaster().fit() then be passed to ets() function in forecast package.

Also, you can specify the parameter model in your customize BaseForecasters, as mentioned above.

Forecast HFModel

forecast() will generate h-step-ahead base forecasts and reconcile the base forecasts to coherent forecasts in bottom level.

>>> forecasts = ols_model.forecast(horizon=12)
>>> all_level_forecasts = ht.aggregate_ts(forecasts)

References

1

Hyndman, R. A. Ahmed, G. Athanasopoulos, and H. L. Shang, “Optimal combination forecasts for hierarchical time series,” Computational Statistics & Data Analysis, vol. 55, no. 9, pp. 2579–2589, Sep. 2011, doi: 10.1016/j.csda.2011.03.006.

2(1,2,3,4)

Wickramasuriya, G. Athanasopoulos, and R. J. Hyndman, “Optimal Forecast Reconciliation for Hierarchical and Grouped Time Series Through Trace Minimization,” Journal of the American Statistical Association, vol. 114, no. 526, pp. 804–819, Apr. 2019, doi: 10.1080/01621459.2018.1448825.