Hierarchical Methods Time series forecasting
—
Probabilistic reconciliation methods that generate prediction intervals and samples from hierarchically coherent distributions. These methods extend point forecasts to probabilistic forecasts while maintaining coherence across all hierarchy levels.
Leverages Gaussian distribution linearity to generate hierarchically coherent prediction distributions under normality assumptions.
class Normality:
"""
Normality Probabilistic Reconciliation Class.
Generates hierarchically coherent prediction distributions assuming
base forecasts follow normal distributions. Uses analytical formulas
to derive reconciled distributions.
"""
def __init__(
self,
S: np.ndarray,
P: np.ndarray,
y_hat: np.ndarray,
sigmah: np.ndarray,
W: np.ndarray,
seed: int = 0
):
"""
Initialize Normality reconciliation.
Parameters:
- S: summing matrix of size (base, bottom)
- P: reconciliation matrix of size (bottom, base)
- y_hat: point forecasts of size (base, horizon)
- sigmah: forecast standard deviations of size (base, horizon)
- W: hierarchical covariance matrix of size (base, base)
- seed: random seed for reproducibility
"""
def get_samples(self, num_samples: int) -> np.ndarray:
"""
Generate coherent samples from normal distribution.
Parameters:
- num_samples: number of samples to generate
Returns:
Coherent samples of size (num_samples, base, horizon)
"""
def get_prediction_quantiles(
self,
results: dict,
quantiles: np.ndarray
) -> dict:
"""
Calculate prediction quantiles for given confidence levels.
Parameters:
- results: dict containing mean forecasts
- quantiles: array of quantile levels (0-1)
Returns:
Updated results dict with quantile forecasts
"""Goes beyond normality assumptions by simulating future sample paths and reconciling them to generate probabilistic forecasts.
class Bootstrap:
"""
Bootstrap Probabilistic Reconciliation Class.
Simulates future sample paths using residual bootstrap from
in-sample errors, then reconciles the paths to generate
coherent probabilistic forecasts.
"""
def __init__(
self,
S: np.ndarray,
P: np.ndarray,
y_hat: np.ndarray,
y_insample: np.ndarray,
y_hat_insample: np.ndarray,
num_samples: int,
seed: int = 0
):
"""
Initialize Bootstrap reconciliation.
Parameters:
- S: summing matrix of size (base, bottom)
- P: reconciliation matrix of size (bottom, base)
- y_hat: point forecasts of size (base, horizon)
- y_insample: historical data for residual calculation
- y_hat_insample: in-sample forecasts for residual calculation
- num_samples: number of bootstrap samples
- seed: random seed for reproducibility
"""
def get_samples(self, num_samples: int) -> np.ndarray:
"""
Generate bootstrap samples of reconciled forecasts.
Parameters:
- num_samples: number of bootstrap samples
Returns:
Bootstrap samples of size (num_samples, base, horizon)
"""
def get_prediction_quantiles(
self,
results: dict,
quantiles: np.ndarray
) -> dict:
"""
Calculate empirical quantiles from bootstrap samples.
Parameters:
- results: dict containing mean forecasts
- quantiles: array of quantile levels (0-1)
Returns:
Updated results dict with bootstrap quantiles
"""Uses empirical bottom-level marginal distributions with rank permutation copulas to generate hierarchically coherent distributions via bottom-up aggregation.
class PERMBU:
"""
PERMBU (Permutation Bootstrap) Probabilistic Reconciliation Class.
Leverages empirical bottom-level marginal distributions with
estimated rank permutation copulas to generate coherent
aggregate-level distributions using bottom-up aggregation.
"""
def __init__(
self,
S: np.ndarray,
P: np.ndarray,
y_hat: np.ndarray,
tags: dict,
y_insample: np.ndarray,
y_hat_insample: np.ndarray,
sigmah: np.ndarray,
num_samples: int,
seed: int = 0
):
"""
Initialize PERMBU reconciliation.
Parameters:
- S: summing matrix of size (base, bottom)
- P: reconciliation matrix of size (bottom, base)
- y_hat: point forecasts of size (base, horizon)
- tags: hierarchy tags for bottom-level identification
- y_insample: historical data for distribution estimation
- y_hat_insample: in-sample forecasts for residual estimation
- sigmah: forecast standard deviations
- num_samples: number of permutation samples
- seed: random seed for reproducibility
"""
def get_samples(self, num_samples: int) -> np.ndarray:
"""
Generate PERMBU samples using rank permutation copulas.
Parameters:
- num_samples: number of samples to generate
Returns:
PERMBU samples of size (num_samples, base, horizon)
"""
def get_prediction_quantiles(
self,
results: dict,
quantiles: np.ndarray
) -> dict:
"""
Calculate quantiles from PERMBU samples.
Parameters:
- results: dict containing mean forecasts
- quantiles: array of quantile levels (0-1)
Returns:
Updated results dict with PERMBU quantiles
"""from hierarchicalforecast.probabilistic_methods import Normality
import numpy as np
# Initialize normality method
normality = Normality(
S=summing_matrix,
P=reconciliation_matrix,
y_hat=point_forecasts,
sigmah=forecast_stds,
W=covariance_matrix,
seed=42
)
# Generate samples
samples = normality.get_samples(num_samples=1000)
# Calculate prediction intervals
results = {'mean': reconciled_forecasts}
quantiles = np.array([0.1, 0.9]) # 80% prediction intervals
results_with_intervals = normality.get_prediction_quantiles(results, quantiles)from hierarchicalforecast.probabilistic_methods import Bootstrap
# Initialize bootstrap method
bootstrap = Bootstrap(
S=summing_matrix,
P=reconciliation_matrix,
y_hat=point_forecasts,
y_insample=historical_data,
y_hat_insample=insample_forecasts,
num_samples=1000,
seed=42
)
# Generate bootstrap samples
samples = bootstrap.get_samples(num_samples=500)
# Calculate bootstrap intervals
results = {'mean': reconciled_forecasts}
quantiles = np.array([0.05, 0.95]) # 90% prediction intervals
bootstrap_intervals = bootstrap.get_prediction_quantiles(results, quantiles)from hierarchicalforecast.probabilistic_methods import PERMBU
# Initialize PERMBU method
permbu = PERMBU(
S=summing_matrix,
P=reconciliation_matrix,
y_hat=point_forecasts,
tags=hierarchy_tags,
y_insample=historical_data,
y_hat_insample=insample_forecasts,
sigmah=forecast_stds,
num_samples=1000,
seed=42
)
# Generate PERMBU samples
samples = permbu.get_samples(num_samples=800)
# Calculate PERMBU intervals
results = {'mean': reconciled_forecasts}
quantiles = np.array([0.025, 0.975]) # 95% prediction intervals
permbu_intervals = permbu.get_prediction_quantiles(results, quantiles)# Compare different probabilistic methods
methods = {
'Normality': Normality(S, P, y_hat, sigmah, W, seed=42),
'Bootstrap': Bootstrap(S, P, y_hat, y_insample, y_hat_insample, 1000, seed=42),
'PERMBU': PERMBU(S, P, y_hat, tags, y_insample, y_hat_insample, sigmah, 1000, seed=42)
}
# Generate samples from each method
samples_dict = {}
for name, method in methods.items():
samples_dict[name] = method.get_samples(num_samples=500)
# Calculate intervals for comparison
quantiles = np.array([0.1, 0.9])
results = {'mean': reconciled_forecasts}
interval_results = {}
for name, method in methods.items():
interval_results[name] = method.get_prediction_quantiles(results.copy(), quantiles)Install with Tessl CLI
npx tessl i tessl/pypi-hierarchicalforecast