Temporal Hierarchical Forecasting on Australian Tourism Data
HierarchicalForecast
to produce coherent forecasts between temporal
levels. We will use the classic Australian Domestic Tourism (Tourism
)
dataset, which contains monthly time series of the number of visitors to
each state of Australia.
We will first load the Tourism
data and produce base forecasts using
an AutoETS
model from StatsForecast
. Then, we reconciliate the
forecasts with several reconciliation algorithms from
HierarchicalForecast
according to a temporal hierarchy.
You can run these experiments using CPU or GPU with Google Colab.
Country | Region | State | Purpose | ds | y | |
---|---|---|---|---|---|---|
0 | Australia | Adelaide | South Australia | Business | 1998-01-01 | 135.077690 |
1 | Australia | Adelaide | South Australia | Business | 1998-04-01 | 109.987316 |
2 | Australia | Adelaide | South Australia | Business | 1998-07-01 | 166.034687 |
3 | Australia | Adelaide | South Australia | Business | 1998-10-01 | 127.160464 |
4 | Australia | Adelaide | South Australia | Business | 1999-01-01 | 137.448533 |
unique_id
to the data.
year
consists of 12
months, so we define a
key, value pair "yearly":12
. We can do something similar for other
aggregations that we are interested in.
In this example, we choose a temporal aggregation of year
,
semiannual
and quarter
. The bottom level timesteps have a quarterly
frequency.
aggregate_temporal
function. Note that we have different aggregation matrices S
for the
train- and test set, as the test set contains temporal hierarchies that
are not included in the train set.
temporal_id | quarter-1 | quarter-2 | quarter-3 | quarter-4 | |
---|---|---|---|---|---|
0 | year-1 | 1.0 | 1.0 | 1.0 | 1.0 |
1 | year-2 | 0.0 | 0.0 | 0.0 | 0.0 |
2 | year-3 | 0.0 | 0.0 | 0.0 | 0.0 |
3 | year-4 | 0.0 | 0.0 | 0.0 | 0.0 |
4 | year-5 | 0.0 | 0.0 | 0.0 | 0.0 |
temporal_id | quarter-1 | quarter-2 | quarter-3 | quarter-4 | |
---|---|---|---|---|---|
0 | year-1 | 1.0 | 1.0 | 1.0 | 1.0 |
1 | year-2 | 0.0 | 0.0 | 0.0 | 0.0 |
2 | semiannual-1 | 1.0 | 1.0 | 0.0 | 0.0 |
3 | semiannual-2 | 0.0 | 0.0 | 1.0 | 1.0 |
4 | semiannual-3 | 0.0 | 0.0 | 0.0 | 0.0 |
make_future_dataframe
helper function for that.
Y_test_df_new
can be then used in
aggregate_temporal
to construct the temporally aggregated structures:
Y_test_df_new
doesnโt contain the ground truth values y
.
temporal_id | quarter-1 | quarter-2 | quarter-3 | quarter-4 | quarter-5 | quarter-6 | quarter-7 | quarter-8 | |
---|---|---|---|---|---|---|---|---|---|
0 | year-1 | 1.0 | 1.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1 | year-2 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 1.0 | 1.0 | 1.0 |
2 | semiannual-1 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
3 | semiannual-2 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
4 | semiannual-3 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 |
5 | semiannual-4 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 1.0 |
6 | quarter-1 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
7 | quarter-2 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
8 | quarter-3 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
9 | quarter-4 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
10 | quarter-5 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
11 | quarter-6 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
12 | quarter-7 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
13 | quarter-8 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
temporal_id | unique_id | ds | y | |
---|---|---|---|---|
0 | year-1 | Australia/ACT/Canberra/Business | 2016-10-01 | 754.139245 |
1 | year-2 | Australia/ACT/Canberra/Business | 2017-10-01 | 809.950839 |
2 | year-1 | Australia/ACT/Canberra/Holiday | 2016-10-01 | 735.365896 |
3 | year-2 | Australia/ACT/Canberra/Holiday | 2017-10-01 | 834.717900 |
4 | year-1 | Australia/ACT/Canberra/Other | 2016-10-01 | 175.239916 |
โฆ | โฆ | โฆ | โฆ | โฆ |
4251 | quarter-4 | Australia/Western Australia/Experience Perth/Vโฆ | 2016-10-01 | 439.699451 |
4252 | quarter-5 | Australia/Western Australia/Experience Perth/Vโฆ | 2017-01-01 | 356.867038 |
4253 | quarter-6 | Australia/Western Australia/Experience Perth/Vโฆ | 2017-04-01 | 302.296119 |
4254 | quarter-7 | Australia/Western Australia/Experience Perth/Vโฆ | 2017-07-01 | 373.442070 |
4255 | quarter-8 | Australia/Western Australia/Experience Perth/Vโฆ | 2017-10-01 | 455.316702 |
temporal_id | unique_id | ds | |
---|---|---|---|
0 | year-1 | Australia/ACT/Canberra/Business | 2016-10-01 |
1 | year-2 | Australia/ACT/Canberra/Business | 2017-10-01 |
2 | year-1 | Australia/ACT/Canberra/Holiday | 2016-10-01 |
3 | year-2 | Australia/ACT/Canberra/Holiday | 2017-10-01 |
4 | year-1 | Australia/ACT/Canberra/Other | 2016-10-01 |
โฆ | โฆ | โฆ | โฆ |
4251 | quarter-4 | Australia/Western Australia/Experience Perth/Vโฆ | 2016-10-01 |
4252 | quarter-5 | Australia/Western Australia/Experience Perth/Vโฆ | 2017-01-01 |
4253 | quarter-6 | Australia/Western Australia/Experience Perth/Vโฆ | 2017-04-01 |
4254 | quarter-7 | Australia/Western Australia/Experience Perth/Vโฆ | 2017-07-01 |
4255 | quarter-8 | Australia/Western Australia/Experience Perth/Vโฆ | 2017-10-01 |
Y_train_df
using the AutoETS
model. Observe that
Y_hat_df
contains the forecasts but they are not coherent.
Note also that both frequency and horizon are different for each
temporal aggregation. In this example, the lowest level has a quarterly
frequency, and a horizon of 8
(constituting 2
years). The year
aggregation thus has a yearly frequency with a horizon of 2
.
It is of course possible to choose a different model for each level in
the temporal aggregation - you can be as creative as you like!
HierarchicalReconciliation
class to reconcile the forecasts. In this example we use
BottomUp
and
MinTrace
.
Note that we have to set temporal=True
in the reconcile
function.
Note that temporal reconcilation currently isnโt supported for insample
reconciliation methods, such as MinTrace(method='mint_shrink')
.
HierarchicalForecast
package includes the
evaluate
function to evaluate the different hierarchies.
We evaluate the temporally aggregated forecasts across all temporal
aggregations.
level | metric | Base | BottomUp | MinTrace(ols) | |
---|---|---|---|---|---|
0 | year | mae | 47.0000 | 50.8000 | 46.7000 |
1 | year | scaled_crps | 0.0562 | 0.0620 | 0.0666 |
2 | semiannual | mae | 29.5000 | 30.5000 | 29.1000 |
3 | semiannual | scaled_crps | 0.0643 | 0.0681 | 0.0727 |
4 | quarter | mae | 19.4000 | 19.4000 | 18.7000 |
5 | quarter | scaled_crps | 0.0876 | 0.0876 | 0.0864 |
6 | Overall | mae | 26.2000 | 27.1000 | 25.7000 |
7 | Overall | scaled_crps | 0.0765 | 0.0784 | 0.0797 |
MinTrace(ols)
is the best overall point method, scoring the lowest
mae
on the year
and semiannual
aggregated forecasts as well as the
quarter
bottom-level aggregated forecasts. However, the Base
method
is better overall on the probabilistic measure crps
, where it scores
the lowest, indicating that the uncertainty levels predicted with the
Base
method are better in this example.
S
matrix shows how the
aggregation 2016
can be obtained by summing the 4 quarters in 2016. *
The second row of the S
matrix shows how the aggregation 2017
can be
obtained by summing the 4 quarters in 2017. * The next 4 rows show how
the semi-annual aggregations can be obtained. * The final rows are the
identity matrix for each quarter, denoting the bottom temporal level
(each quarter).