# HierarchicalForecast turns disagreeing forecasts into one coherent set

> HierarchicalForecast is a Python library that reconciles independent time series forecasts across aggregation levels, so regional totals, national totals and bottom level series stop contradicting each other. It reconciles rather than forecasts, which makes it a companion to StatsForecast rather than a replacement for it.

**Nixtla/hierarchicalforecast** — Probabilistic Hierarchical forecasting 👑 with statistical and econometric methods.

- Repository: https://github.com/Nixtla/hierarchicalforecast
- Website: https://nixtlaverse.nixtla.io/hierarchicalforecast
- Stars: 765 · Forks: 99
- Language: Python
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/nixtla-hierarchicalforecast

## Why incoherent totals break planning

Most retail and supply chain datasets arrive already aggregated: a national total, regional subtotals, and store level rows beneath them. Forecast each layer independently and the numbers stop adding up. A regional forecast that sums to more than the country forecast it sits inside is not a rounding artefact, it is a contradiction that propagates into every plan built on top of it.

HierarchicalForecast exists to remove that contradiction at the point where it is created. The library targets forecasters who already hold base predictions and need them to be mutually consistent across a hierarchy. It does not forecast on its own. It reconciles. Base forecasts come from a separate model, StatsForecast in the documented example, and this package adjusts them so that every level agrees with every other level.

## The hierarchy specification drives everything

The core input is a specification of how series aggregate. In the example, HierarchicalData.load returns three objects: the long format series Y_df, a specification frame S_df that describes which series roll up into which, and a tags frame. The specification is what turns a stack of independent forecasts into a system that can be made coherent.

Internally the package builds a summation matrix from that specification and applies a reconciliation matrix so the corrected bottom level series still aggregate to the corrected totals. The projection depends on structure rather than on any single series, so the package ships a compiled extension. setup.py defines a pybind11 module named hierarchicalforecast._lib, compiled from src/*.cpp, with Eigen headers vendored under external_libs/eigen and a C++20 standard.

That build is where the friction sits. Compiler flags differ per platform. Linux and Windows receive OpenMP and fast math options, and macOS expects libomp installed through Homebrew. If brew is missing, setup.py catches the failure and continues without those include and library paths.

## BottomUp, TopDown and MiddleOut in practice

Three of the classic methods share one interface and one call. BottomUp simply adds the lower levels to produce the upper levels, which is cheap and assumes the base series are more reliable than the aggregates. TopDown does the reverse, distributing a top level forecast down the tree. MiddleOut picks a level in the middle and anchors the base predictions there, using bottom up above that anchor and top down below it.

The reconcilers are constructed with the level names taken from your specification. The example anchors MiddleOut on Country/Purpose/State and asks TopDown for forecast proportions rather than an equal split.

The three imports the example needs are below. The packages statsforecast and datasetsforecast are additional requirements for this example and are not installed by the library itself.

```python
from datasetsforecast.hierarchical import HierarchicalData

# compute base forecast no coherent
from statsforecast.core import StatsForecast
from statsforecast.models import AutoARIMA, Naive

#obtain hierarchical reconciliation methods and evaluation
from hierarchicalforecast.core import HierarchicalReconciliation
from hierarchicalforecast.evaluation import evaluate
from hierarchicalforecast.methods import BottomUp, TopDown, MiddleOut
from utilsforecast.losses import mse
```

## Load the data, split it, and produce base forecasts

The workflow is short. Load the hierarchical dataset, keep the last four periods of each series as a test set, fit the base models on what remains, and hand the resulting predictions to the reconcilers. The frequency is set to QE, quarterly end, and the base model set is AutoARIMA alongside a Naive baseline so that the reconciled result can be compared against an unreconciled forecast.

Because the frequency is passed to StatsForecast and not to this library, the hierarchy specification and the base forecast frame have to agree on the time axis and on the unique_id naming. A mismatch in either shows up as a reconciliation that returns an empty or misaligned frame rather than an error you can read off the console.

After this step the frame Y_hat_df holds base forecasts for every series at every level, still incoherent.

```python
# Load TourismSmall dataset
Y_df, S_df, tags = HierarchicalData.load('./data', 'TourismSmall')
Y_df['ds'] = pd.to_datetime(Y_df['ds'])
S_df = S_df.reset_index(names="unique_id")

#split train/test sets
Y_test_df  = Y_df.groupby('unique_id').tail(4)
Y_train_df = Y_df.drop(Y_test_df.index)

# Compute base auto-ARIMA predictions
fcst = StatsForecast(models=[AutoARIMA(season_length=4), Naive()],
                     freq='QE', n_jobs=-1)
Y_hat_df = fcst.forecast(df=Y_train_df, h=4)
```

## The reconciler object is where the method choice is made

Reconciliation happens through a single object, HierarchicalReconciliation, constructed with a list of reconcilers. Passing three reconcilers produces three reconciled sets, one per method, so an accuracy comparison across methods does not require rewriting the pipeline. The evaluation module and the evaluate function sit alongside it, and the example pulls mse from utilsforecast.losses to score the results.

Two of the documented TopDown variants are visible here. forecast_proportions distributes the top level according to the historical proportions of the series beneath it, which is the safer default when bottom level series have different scales. The MiddleOut instance takes the same top_down_method argument, so the propagation rule applies to the levels below the anchor only.

This design keeps the method selection declarative. The cost is that every method shares one call signature, so a method specific argument that does not apply to a given hierarchy raises at construction time rather than at reconcile time.

```python
reconcilers = [
    BottomUp(),
    TopDown(method='forecast_proportions'),
    MiddleOut(middle_level='Country/Purpose/State',
              top_down_method='forecast_proportions')
]
hrec = HierarchicalReconciliation(reconcilers=reconcilers)
```

## MinTrace, ERM and the solver underneath

BottomUp and TopDown impose no error structure. MinTrace goes further: it minimises the total forecast variance of the space of coherent forecasts, using a closed form solution based on the variance covariance matrix of the base forecast errors. ERM takes a different route and optimises the reconciliation matrix under an L1 regularised objective, which the package solves with the qpsolvers dependency and its clarabel extra.

That solver dependency is the practical difference between the classical and the alternative methods. BottomUp and TopDown are arithmetic. MinTrace needs an invertible matrix and sensible error estimates. ERM needs an optimiser, and the practical hierarchy size at which it stops being a good idea is not documented anywhere in the project.

The package is explicit about where it sits in the stack. It is a library of statistical and econometric baselines with an accompanying paper, and the repository layout separates experiments, external libraries and documentation scripts from the package source itself.

## Probabilistic reconciliation and the limits of conformal coverage

Coherence applies to distributions as much as to point forecasts, and the package ships four probabilistic methods. Normality uses the MinTrace variance covariance closed form under a normality assumption. Bootstrap generates a distribution of hierarchically reconciled predictions using the approach attributed to Gamakumara. PERMBU reconciles independent sample predictions by reinjecting multivariate dependence with estimated rank permutation copulas and then performing a bottom up aggregation. Conformal produces distribution free prediction intervals using conformal prediction.

Conformal carries an explicit condition. The project states that it provides valid coverage under exchangeability assumptions. If your series are not exchangeable, that is a modelling assumption you are making, and the guarantee does not hold. There is no tutorial here for diagnosing exchangeability, so this is a decision the practitioner has to make elsewhere.

Temporal hierarchies are supported too. All reconciliation methods except the in sample methods are available for temporal hierarchies, which means a weekly, monthly and yearly structure can be reconciled with the same code path as a cross sectional one.

## Installing the package and its compiled extension

The project recommends uv as the package manager and gives the standard installer as an alternative. Both install the same distribution from the Python package index.

```python
uv pip install hierarchicalforecast
```

```python
pip install hierarchicalforecast
```

The package metadata requires Python 3.10 up to 4.0, and the classifiers list 3.10 through 3.14. The distribution is marked as a beta release in its own metadata, which is worth knowing before you pin it in a production pipeline.

Dependencies are deliberately light: numpy, pandas, scikit-learn, matplotlib, narwhals, qpsolvers with clarabel, and utilsforecast. Polars is available as an optional extra, and the example notebook lives in the repository and can be opened directly in Colab, which is the shortest route to seeing a complete reconciliation run end to end.

## What the library does not cover

Three boundaries are worth stating plainly. First, HierarchicalForecast does not produce base forecasts. Without a separate modelling step, such as the StatsForecast and AutoARIMA pairing shown here, there is nothing to reconcile, and the library cannot fill that gap.

Second, the hierarchy specification is your responsibility. The package will reconcile the tree you describe, correctly and without complaint, so an incorrect tree produces incorrect coherent forecasts rather than an error.

Third, the macOS build path assumes libomp can be located through brew. The setup script tolerates a missing Homebrew, but the resulting binary is compiled without the OpenMP flags that the Linux and Windows paths request, and the project does not describe the performance or build consequences of that difference.

On maintenance, the repository is not archived and the last push was on 2026-10-19, with release v1.5.3 published on 2026-09-24 after v1.5.2 on 2026-08-06. The licence is Apache-2.0, and a THIRD_PARTY_LICENSES.md file plus a pip-licenses based Makefile target indicate that bundled third party licences are tracked separately from the main licence.

## Conclusion

Adopt HierarchicalForecast when you forecast many series that aggregate into each other and the totals must reconcile, and expect to pair it with StatsForecast or an equivalent base model. Skip it for single level series, for pure deep learning forecasting, or if a compiled Eigen and pybind11 build is a problem for your environment. Before committing, check that your hierarchy specification S_df matches how your business actually aggregates, because the reconciliation matrix is derived from that specification and nothing in the library can correct a wrong tree.

## FAQ

### Does HierarchicalForecast produce forecasts on its own?

No. It reconciles base forecasts that come from another model, StatsForecast with AutoARIMA in the documented example, so that values across aggregation levels are consistent.

### How do I install HierarchicalForecast?

The project recommends uv, with uv pip install hierarchicalforecast, and gives pip install hierarchicalforecast as the alternative. The distribution requires Python 3.10 or later below 4.0, and it builds a pybind11 and Eigen extension at install time.

### Which reconciliation methods work with temporal hierarchies?

All of the reconciliation methods except the in sample methods are available for temporal hierarchies, so weekly, monthly and yearly structures can be reconciled the same way as cross sectional ones.

### What does the HierarchicalForecast package require besides base forecasts?

A hierarchy specification describing which series aggregate into which, returned as S_df by HierarchicalData.load, plus matching unique_id names and time frequency between that specification and the base forecast frame.

## Sources

- [License: Apache-2.0](https://github.com/Nixtla/hierarchicalforecast/blob/main/LICENSE)
- [Nixtla/hierarchicalforecast on GitHub](https://github.com/Nixtla/hierarchicalforecast)
- [Project website](https://nixtlaverse.nixtla.io/hierarchicalforecast)
- [README](https://github.com/Nixtla/hierarchicalforecast/blob/main/README.md)
- [Releases](https://github.com/Nixtla/hierarchicalforecast/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nixtla-hierarchicalforecast
