Models & ensembles reference¶
scale-forecasting ships 37 built-in forecasting models (31 Python models, 4 Vertex AI AutoML models, and 2 BigQuery-native SQL models) alongside 9 ensemble blending and stacking strategies and 8 hierarchical forecast reconciliation methods. Every model implements the BaseModel contract in its own module under src/scale_forecasting/models/ and registers itself at import time.
When a run is submitted, the orchestrator groups the requested models by family (statistical, ml, deep_learning, automl, and native) and routes each family to its designated compute runtime in parallel.
flowchart TD
Base["BaseModel Contract (models/base_model.py)<br/>fit(y, X) · predict(horizon, X, quantiles)<br/>fit_panel(panel, ...) · predict_panel(horizon, ...)<br/>feature_attributions · search_space(trial) · recondition(y, X)"]
subgraph Stat["Family: statistical (18 Python Models — Spark / Ray / Vertex / GCE / GKE)"]
direction TB
S1["Baselines, Spectral & Intermittent<br/>naive_mean · naive_seasonal · naive_drift<br/>naive_moving_average · croston · fft"]
S2["Exponential Smoothing & Decomposition<br/>theta · auto_theta · holtwinters · autoets<br/>auto_ces · tbats · stl_bagging"]
S3["ARIMA, State-Space & Additive<br/>auto_arima · sarimax · ucm · kalman · prophet"]
end
subgraph ML["Family: ml (5 Python Models via _lag_forecaster.py — Spark / Ray / Vertex / GCE / GKE)"]
M1["Recursive & Direct Target Lags + Calendar & Exog + Two-Tier Explainability<br/>regression_lags · random_forest · lightgbm · xgboost · catboost"]
end
subgraph DL["Family: deep_learning (8 Python Models — Spark / Ray / Vertex / GCE / GKE CPU or GPU)"]
direction TB
D1["PyTorch Local, Global & Hybrid Panel Forecasters<br/>neuralprophet · tide · tft · tsmixer · patchtst"]
D2["Open-Weight Zero-Shot Foundation Forecasters<br/>chronos_bolt · chronos2 · timesfm_torch"]
end
subgraph AML["Family: automl (4 Vertex AI AutoML / Tabular Workflow Models — vertex_automl)"]
A1["Managed Global KFP v2 Pipelines + Reusable Stage-1 HPO + Explainability<br/>vertex_l2l · vertex_tide · vertex_tft · vertex_seq2seq"]
end
subgraph Nat["Family: native (2 BigQuery SQL Models — BigQuery ML)"]
N1["Serverless SQL Execution<br/>arima_plus / arima_plus_xreg (ARIMA_PLUS / ARIMA_PLUS_XREG + ML.EXPLAIN_FORECAST + ML.ARIMA_EVALUATE)<br/>timesfm / bq_timesfm (AI.FORECAST 2.0 / 2.5 / 3.0 + Multivariate Covariates)"]
end
Rec["Hierarchical Reconciliation (reconciliation.py)<br/>bottom_up · top_down · middle_out · ols · wls_struct · wls_var · mint_shrink · mint_nonneg"]
Ens["Ensemble Engine (Driver Pandas + Storage Write API)<br/>Calculated & Selection: mean · median · trimmed_mean · inverse_error · champion · horizon_specialist<br/>Learned Stacking: nnls · ridge · xgb"]
Base --> Stat & ML & DL & AML & Nat
Stat & ML & DL & AML & Nat --> Rec --> Ens
Complete model catalog¶
Every model declares its upstream open-source package (package and package_url on BaseModel), execution family, univariate & three-tier covariate support (supports_future_covariates, supports_past_covariates, supports_static_covariates), two-tier feature attribution support (supports_explainability), supported training modes (local, global, hybrid), hierarchical reconciliation support, and fast state updates (expanding_frozen backtesting via supports_recondition).
| Model | Family | Runtime | Upstream Package | Univariate | Covariates (Future / Past / Static) |
Explainability (attributions_df) |
Training Modes | Reconciliation | Native Intervals | Frozen Origin (recondition) |
Methodology & Summary |
|---|---|---|---|---|---|---|---|---|---|---|---|
naive_mean |
statistical |
Python | numpy |
Yes | No / No / No | Structural | local |
All 8 FPP3 | No | No | Constant forecast equal to the training sample mean with empirical residual intervals. |
naive_seasonal |
statistical |
Python | numpy |
Yes | No / No / No | Structural | local |
All 8 FPP3 | No | Yes | Repeats the final observed seasonal cycle (m derived from data.freq). |
naive_drift |
statistical |
Python | numpy |
Yes | No / No / No | Structural | local |
All 8 FPP3 | No | Yes | Linear trend extrapolation between the first and last training observations. |
naive_moving_average |
statistical |
Python | numpy |
Yes | No / No / No | Structural | local |
All 8 FPP3 | No | Yes | Flat forecast equal to the mean of the trailing window observations. |
croston |
statistical |
Python | numpy |
Yes | No / No / No | Structural | local |
All 8 FPP3 | No | Yes | Intermittent-demand decomposition (classic, sba, or tsb variant) for zero-heavy series. |
fft |
statistical |
Python | scipy |
Yes | No / No / No | Structural | local |
All 8 FPP3 | No | No | Discrete Fourier Transform spectral extrapolation with polynomial trend detrending (scipy.fft.rfft). |
theta |
statistical |
Python | statsmodels |
Yes | No / No / No | Structural | local |
All 8 FPP3 | Yes | No | Assimakopoulos-Nikolopoulos Theta decomposition (statsmodels.tsa.forecasting.theta.ThetaModel). |
auto_theta |
statistical |
Python | statsforecast |
Yes | No / No / No | Structural | local |
All 8 FPP3 | Yes | No | Automated Theta selection across Standard, Optimized (OTM), Dynamic (DSTM, DOTM) variants (AutoTheta). |
holtwinters |
statistical |
Python | statsmodels |
Yes | No / No / No | Structural | local |
All 8 FPP3 | No | Yes | Additive Holt-Winters seasonal exponential smoothing (ExponentialSmoothing). |
autoets |
statistical |
Python | statsmodels |
Yes | No / No / No | Structural | local |
All 8 FPP3 | Yes | Yes | State-space Error-Trend-Seasonal model (ETSModel) with analytical prediction intervals. |
auto_ces |
statistical |
Python | statsforecast |
Yes | No / No / No | Structural | local |
All 8 FPP3 | Yes | No | Automated Complex Exponential Smoothing (AutoCES) across "N", "S", "P", and "F" seasonality. |
tbats |
statistical |
Python | statsforecast |
Yes | No / No / No | Structural | local |
All 8 FPP3 | Yes | No | Trigonometric seasonality, Box-Cox transform, ARMA errors, Trend, and Seasonal components (AutoTBATS). |
stl_bagging |
statistical |
Python | statsmodels |
Yes | No / No / No | Structural | local |
All 8 FPP3 | Yes | No | Bergmeir-Hyndman-Benítez STL decomposition with moving-block-bootstrapped ETS ensembles. |
auto_arima |
statistical |
Python | statsforecast |
Yes | Yes / Yes / No | Structural | local |
All 8 FPP3 | Yes | No | Hyndman-Khandakar stepwise AICc seasonal ARIMA order search (AutoARIMA) with exogenous regressors. |
sarimax |
statistical |
Python | statsmodels |
Yes | Yes / Yes / No | Structural | local |
All 8 FPP3 | Yes | Yes | Seasonal ARIMA with exogenous regressors (SARIMAX) and analytical state-space intervals. |
ucm |
statistical |
Python | statsmodels |
Yes | Yes / Yes / No | Structural | local |
All 8 FPP3 | Yes | Yes | Structural Unobserved Components state-space model (UnobservedComponents) with local linear trend. |
kalman |
statistical |
Python | statsmodels |
Yes | Yes / Yes / No | Structural | local |
All 8 FPP3 | Yes | Yes | Linear Gaussian state-space Kalman filter (UnobservedComponents) with trigonometric seasonal harmonics. |
prophet |
statistical |
Python | prophet |
Yes | Yes / Yes / No | Structural | local |
All 8 FPP3 | Yes | No | Piecewise linear/logistic trend, multi-period Fourier seasonality, holidays, and exogenous regressors. |
regression_lags |
ml |
Python | scikit-learn |
Yes | Yes / Yes / No | Tier 1 + Tier 2 (Linear) | local |
All 8 FPP3 | No | Yes | L2-regularized Ridge regression over recursive or direct target lags (1, 2, 3, 7, 14, 28), calendar features, exog, and exact linear attributions. |
random_forest |
ml |
Python | scikit-learn |
Yes | Yes / Yes / No | Tier 1 + Tier 2 (Deviation) | local |
All 8 FPP3 | No | Yes | Bagged decision tree ensemble (RandomForestRegressor) over recursive or direct target lags, calendar features, and exog. |
lightgbm |
ml |
Python | lightgbm |
Yes | Yes / Yes / No | Tier 1 + Tier 2 (TreeSHAP) | local |
All 8 FPP3 | No | Yes | Gradient-boosted decision trees (LGBMRegressor) over recursive or direct target lags, calendar features, and exog with TreeSHAP attributions. |
xgboost |
ml |
Python | xgboost |
Yes | Yes / Yes / No | Tier 1 + Tier 2 (TreeSHAP) | local |
All 8 FPP3 | No | Yes | Histogram-based gradient-boosted trees (XGBRegressor) over recursive or direct target lags, calendar features, and exog with TreeSHAP attributions. |
catboost |
ml |
Python | catboost |
Yes | Yes / Yes / No | Tier 1 + Tier 2 (ShapValues) | local |
All 8 FPP3 | No | Yes | Symmetric (oblivious) gradient-boosted trees (CatBoostRegressor) over recursive or direct target lags, calendar, and exog with ShapValues. |
neuralprophet |
deep_learning |
Python | neuralprophet |
Yes | No / No / No | Structural | local, global, hybrid |
All 8 FPP3 + Global Panel | Yes | No | PyTorch AR-Net with piecewise trend, Fourier seasonality, and quantile heads (0.1, 0.5, 0.9). |
tide |
deep_learning |
Python | neuralforecast |
Yes | Yes / Yes / Yes | Structural | local, global |
All 8 FPP3 + Global Panel | Yes | No | Time-series Dense Encoder (TiDE, Das et al. 2023) with future, past, and static covariates and MQLoss quantiles. |
tft |
deep_learning |
Python | neuralforecast |
Yes | Yes / Yes / Yes | Structural | local, global |
All 8 FPP3 + Global Panel | Yes | No | Temporal Fusion Transformer (TFT, Lim et al. 2021) with variable selection networks and interpretable multi-head attention. |
tsmixer |
deep_learning |
Python | neuralforecast |
Yes | Yes / Yes / Yes | Structural | local, global |
All 8 FPP3 + Global Panel | Yes | No | All-MLP time- and feature-mixing network (TSMixerx, Chen et al. 2023) with future, past, and static covariates. |
patchtst |
deep_learning |
Python | neuralforecast |
Yes | No / No / No | Structural | local, global |
All 8 FPP3 + Global Panel | Yes | No | Channel-independent subseries-patch Transformer (PatchTST, Nie et al. 2023) with MQLoss quantile heads. |
chronos_bolt |
deep_learning |
Python | chronos-forecasting |
Yes | No / No / No | Structural | local, global |
All 8 FPP3 + Global Panel | Yes | Yes | Amazon Chronos-Bolt zero-shot patch-based T5 foundation model (amazon/chronos-bolt-base default, small / mini / tiny selectable) with native decile heads. |
chronos2 |
deep_learning |
Python | chronos-forecasting |
Yes | Yes / Yes / Yes | Structural | local, global |
All 8 FPP3 + Global Panel | Yes | Yes | Amazon Chronos-2 zero-shot foundation model (amazon/chronos-2) with group attention across future, past, and static covariates and panel cross_learning. |
timesfm_torch |
deep_learning |
Python | timesfm |
Yes | Yes / Yes / Yes | Structural | local, global |
All 8 FPP3 + Global Panel | Yes | Yes | Google Research open-weight PyTorch TimesFM 3.0 (google/timesfm-3.0-pytorch default with native Variate Attention over covariates) and TimesFM 2.5 (version="2.5" / @v2.5). |
vertex_l2l |
automl |
Vertex AutoML | google-cloud-pipeline-components |
Yes | Yes / Yes / Yes | Tier 1 + Tier 2 (Vertex Baseline) | global |
All 8 FPP3 + Global Panel | Yes | No | Managed Vertex AI AutoML / Learn-to-Learn neural architecture search & ensemble with reusable Stage-1 HPO and explainability. |
vertex_tide |
automl |
Vertex AutoML | google-cloud-pipeline-components |
Yes | Yes / Yes / Yes | Tier 1 + Tier 2 (Vertex Baseline) | global |
All 8 FPP3 + Global Panel | Yes | No | Managed Vertex AI Time-series Dense Encoder (TiDE) Tabular Workflow with reusable Stage-1 HPO and explainability. |
vertex_tft |
automl |
Vertex AutoML | google-cloud-pipeline-components |
Yes | Yes / Yes / Yes | Tier 1 + Tier 2 (Vertex Baseline) | global |
All 8 FPP3 + Global Panel | Yes | No | Managed Vertex AI Temporal Fusion Transformer (TFT) Tabular Workflow with attention & baseline attributions. |
vertex_seq2seq |
automl |
Vertex AutoML | google-cloud-pipeline-components |
Yes | Yes / Yes / Yes | Tier 1 + Tier 2 (Vertex Baseline) | global |
All 8 FPP3 + Global Panel | Yes | No | Managed Vertex AI Sequence-to-Sequence (Seq2Seq+) encoder-decoder Tabular Workflow with two-tier explainability. |
arima_plus |
native |
BigQuery | bigquery-ml |
Yes | Yes / No / No | Tier 1 + Tier 2 (ML.EXPLAIN_FORECAST) | local |
N/A (SQL) | Yes | No | BigQuery ML ARIMA_PLUS / ARIMA_PLUS_XREG (arima_plus_xreg alias) with custom country holiday CTEs, future covariates, ML.EXPLAIN_FORECAST attributions, ML.ARIMA_EVALUATE / ML.ARIMA_COEFFICIENTS diagnostics, and ML.DETECT_ANOMALIES / ML.DETECT_CHANGE_POINTS. |
timesfm |
native |
BigQuery | bigquery-ml |
Yes | Yes / Yes / No | Structural | local (zero-shot) |
N/A (SQL) | Yes | No | Zero-shot foundation-model forecasting via BigQuery AI.FORECAST (bq_timesfm alias; TimesFM 2.0, TimesFM 2.5 univariate default, or TimesFM 3.0 with future_covariates and past_covariates via target_cols => ['y']) plus AI.DETECT_ANOMALIES. |
Covariate tiers & mixed-model fallback policy¶
- Univariate-only runs require no
featurescovariate fields (future_covariates: [],past_covariates: [],static_covariates: [],exog: []). All 37 models support univariate forecasting. - Three covariate tiers when configured under
features: future_covariates(exogalias): known across both history and the forecast horizon (e.g. promotions, scheduled prices, calendar events). Supported by 21 models (auto_arima,sarimax,ucm,kalman,prophet, all 5mlmodels,tide,tft,tsmixer,chronos2,timesfm_torch, all 4automlmodels,arima_plusviaARIMA_PLUS_XREG, andtimesfmviaTimesFM 3.0).past_covariates: observed historically up tocutoff_dateand masked in validation/future windows during rolling-origin backtesting and HPO so future actuals never leak. Supported by 20 dynamic-covariate models (natively as historical encoders intide,tft,tsmixer,chronos2,timesfm_torch,automlmodels, andtimesfmviaTimesFM 3.0, or viaexog_lags/ cutoff carry-forward inmlandstatisticalmodels).static_covariates: time-invariant per-series metadata (region,category). Consumed by the cross-seriesneuralforecastand open-weight foundation architectures (tide,tft,tsmixer,chronos2,timesfm_torch) and all 4automlmodels (vertex_l2l,vertex_tide,vertex_tft,vertex_seq2seq).- Mixed univariate + covariate runs (
features.on_unsupported_covariates): "fallback"(default): A multi-model run mixing covariate-capable and univariate models (e.g.["theta", "xgboost", "tide"]with all three covariate tiers) logs a clear preflight warning per model and strips unsupported tiers (and theirexog_lags) for that model across fit, backtesting, and HPO—so univariate models run on their full, un-truncated target history."error"(override): Fails fast atdag.check_model_paramswith aConfigErrornaming every model and the covariate tier(s) it does not support.
Model families & hyperparameter reference¶
Per-model hyperparameters can be authored statically under model_params.<model_name> in the run configuration or tuned automatically with Optuna when hpo.enabled: true.
Tagged model variants (<base_model>@<tag>)¶
Any of the 37 registered models can be listed multiple times in models using the <base_model>@<tag> syntax (for example, xgboost@univariate, xgboost@direct, tide@global_cov_all, tide@local_univariate, neuralprophet@hybrid_univariate, chronos_bolt@tiny, timesfm_torch@v2.5, croston@classic, croston@tsb). Each tagged entry executes as an independent model in forecast_predictions, backtest_oof, forecast_metadata, and ensemble/reconciliation pipelines while resolving to <base_model> for class lookup:
- Per-variant hyperparameter overrides:
model_paramsaccepts keys for either the base name (model_params.xgboost) or the full tagged name (model_params["xgboost@direct"]), merging variant-specific overrides on top of base defaults. Whenhpo.enabled: true, Optuna tunes tunable hyperparameters while preserving explicit variant pins (such asstrategy: "direct",variant: "tsb", ortraining_mode: "global"). - Per-variant covariate & feature-ablation tags: Suffixes declared in
worker.pyautomatically filter the exogenous feature matrixXpassed to that variant so side-by-side covariate ablations run in a single job: @univariate/@local_univariate/@global_univariate/@hybrid_univariate— strips all exogenous covariates (X = None), fitting the model purely on the target history.@cov_<col>— restrictsXto a single covariate column<col>(plus any matching<col>_lag_*columns).@cov_drop_<col>— drops<col>(and<col>_lag_*) while keeping all other covariates (leave-one-covariate-out ablation).@no_holidays— drops country-holiday indicator columns while keeping all other features.@no_lags— drops engineered exogenous lag columns (*_lag_*) while keeping contemporaneous covariates.
1. Statistical family (statistical)¶
Models in the statistical family fit per-series time-series equations on CPU workers (Spark, Ray, Vertex CustomJob, GCE, or GKE).
Baselines, intermittent demand & spectral models¶
| Model | Upstream Package | Authored model_params & Defaults |
Optuna search_space |
Notes |
|---|---|---|---|---|
naive_mean |
numpy |
— | — | Predicts the arithmetic mean of training observations. |
naive_seasonal |
numpy |
— | — | Tiles the last $m$ observations forward ($m = 7$ daily, $52$ weekly, $12$ monthly, $24$ hourly). |
naive_drift |
numpy |
— | — | Extrapolates the average step change $(y_T - y_1) / (T - 1)$. |
naive_moving_average |
numpy |
window: 7 (int >= 1) |
window $\in [2, 56]$ |
Predicts the trailing window-step mean; clamps to series length on short series. |
croston |
numpy |
alpha: 0.1, variant: "sba" ("classic" | "sba" | "tsb"), beta: 0.1 |
alpha $\in [0.02, 0.5]$, variant $\in {\text{classic}, \text{sba}, \text{tsb}}$, beta $\in [0.02, 0.5]$ |
Decomposes intermittent demand into non-zero demand size and inter-arrival interval (Syntetos-Boylan or Teunter-Syntetos-Babai). |
fft |
scipy |
K: 10 (top frequencies), trend_poly_degree: 1 (0..3) |
K $\in [2, 30]$, trend_poly_degree $\in [0, 2]$ |
Detrends with a polynomial of degree trend_poly_degree, filters to the K highest-amplitude rfft harmonics, and projects forward analytically. |
Exponential smoothing, Theta & decomposition models¶
| Model | Upstream Package | Authored model_params & Defaults |
Optuna search_space |
Notes |
|---|---|---|---|---|
theta |
statsmodels |
theta: 2.0 (float > 1.0) |
theta $\in [1.1, 4.0]$ |
Deseasonalizes when the series spans at least $2m$ observations and passes an ACF seasonal test. |
auto_theta |
statsforecast |
decomposition_type: "additive" ("additive" | "multiplicative"), model: None ("STM" | "OTM" | "DSTM" | "DOTM") |
decomposition_type $\in {\text{additive}, \text{multiplicative}}$ |
Evaluates standard, optimized, and dynamic Theta specifications via statsforecast.models.AutoTheta. |
holtwinters |
statsmodels |
damped_trend: False |
damped_trend $\in {\text{True}, \text{False}}$ |
Fits additive trend and seasonality; falls back to trend-only if the series has fewer than $2m$ observations. |
autoets |
statsmodels |
damped_trend: True |
damped_trend $\in {\text{True}, \text{False}}$ |
State-space ETSModel with L-BFGS maximum likelihood estimation and analytical state-space intervals. |
auto_ces |
statsforecast |
model: "Z" ("Z" | "N" | "S" | "P" | "F") |
model $\in {\text{Z}, \text{N}, \text{S}, \text{P}}$ |
Complex Exponential Smoothing (statsforecast.models.AutoCES); "Z" selects information-criterion optimal seasonality. |
tbats |
statsforecast |
use_boxcox: None, use_trend: None, use_damped_trend: None, use_arma_errors: True |
use_trend $\in {\text{True}, \text{False}, \text{None}}$, use_damped_trend $\in {\text{True}, \text{False}, \text{None}}$, use_arma_errors $\in {\text{True}, \text{False}}$ |
Trigonometric seasonal representation (AutoTBATS) capable of modeling complex and non-integer seasonal cycles. |
stl_bagging |
statsmodels |
n_bags: 10, block_size: None (defaults to $2m$) |
n_bags $\in [5, 20]$ |
Decomposes series via STL, applies moving-block bootstrap to the remainder, fits an ETSModel per bag, and takes empirical quantiles across the bag ensemble. |
ARIMA, state-space & structural additive models¶
| Model | Upstream Package | Authored model_params & Defaults |
Optuna search_space |
Notes |
|---|---|---|---|---|
auto_arima |
statsforecast |
max_p: 3, max_q: 3, max_P: 1, max_Q: 1, max_d: 2, max_D: 1, stepwise: True, seasonal: True |
max_p $\in [1, 5]$, max_q $\in [1, 5]$, seasonal $\in {\text{True}, \text{False}}$ |
Hyndman-Khandakar automatic seasonal ARIMA order selection (AutoARIMA) with native exogenous regressor support. |
sarimax |
statsmodels |
order: (1, 1, 1) |
p $\in [0, 2]$, d $\in [0, 1]$, q $\in [0, 2]$ |
Fixed-order SARIMAX with seasonal order $(1, 0, 1, m)$ when length $\ge 3m$, plus exogenous regressors. |
ucm |
statsmodels |
level: "local linear trend", freq_seasonal_harmonics: 2 |
level $\in {\text{local level}, \text{local linear trend}, \text{smooth trend}}$, freq_seasonal_harmonics $\in [1, 4]$ |
Structural state-space decomposition (UnobservedComponents) with frequency-domain seasonal harmonics and exog. |
kalman |
statsmodels |
level: "local linear trend", harmonics: 3, autoregressive: 0 (0..3) |
level $\in {\text{local level}, \text{local linear trend}, \text{random walk with drift}}$, harmonics $\in [1, 5]$, autoregressive $\in [0, 2]$ |
State-space Kalman filter (UnobservedComponents) combining stochastic state transitions, seasonal harmonics, optional AR($p$) innovations, and exog. |
prophet |
prophet |
changepoint_prior_scale: 0.05, seasonality_prior_scale: 10.0, seasonality_mode: "additive" |
changepoint_prior_scale $\in [10^{-3}, 0.5]$, seasonality_prior_scale $\in [0.01, 10.0]$, seasonality_mode $\in {\text{additive}, \text{multiplicative}}$ |
Piecewise trend + Fourier seasonality + exogenous covariates via cmdstanpy L-BFGS optimization. |
2. Tabular machine learning family (ml)¶
All five models in the ml family share the autoregressive lag engine in _lag_forecaster.py:
- Feature matrix construction: Automatically constructs target lags (default
lags: [1, 2, 3, 7, 14, 28], customizable per model and automatically dropping any lag $\ge \lfloor T/2 \rfloor$ on short series), four deterministic calendar features (dow,dom,month,doy), and any configured dynamicfeaturescolumns (holidays,fourier,level_shift,exog,future_covariates,past_covariates,exog_lags). - Recursive vs. direct multi-step forecasting (
strategy: "recursive" | "direct"): "recursive"(default): Fits a single 1-step-ahead estimator (build_lag_matrix) and rolls predictions forward across $h \in {1, \dots, H}$ (recursive_predict), appending each predicted $\hat{y}_{T+h}$ to the target history buffer so subsequent steps read recursive lags. Historical-onlypast_covariatesare carried forward from the last observed cutoff value without lookahead into the validation window."direct": Fits an independent horizon-specific estimator $f_h$ for each step $h \in {1, \dots, H}$ directly against $y_{t+h-1}$ using fixed forecast-origin target lags $y_{t-\ell}$ alongside step-$h$ calendar and future covariates (fit_direct_models/direct_predict/direct_explain), eliminating recursive error accumulation at longer horizons. Compare both side-by-side in a single run using tagged model variants (for example,["xgboost", "xgboost@direct"]withmodel_params: {"xgboost@direct": {"strategy": "direct"}}).- Two-tier feature attributions (
supports_explainability = True): Computes exact per-horizon-step local attributions (forecast_predictions.explanations) and series-level driver importance (forecast_metadata.fit_diagnostics["feature_attributions"]) for both"recursive"and"direct"strategies using native C++ TreeSHAP (xgboost,lightgbm,catboost), closed-form linear weights (regression_lags), or importance-weighted feature deviations (random_forest). - Fast state updates (
expanding_frozen): Appends newly observed actuals to the lag history buffer without re-fitting tree or regression weights (supports_recondition = True).
| Model | Upstream Package | Authored model_params & Defaults |
Optuna search_space |
Notes |
|---|---|---|---|---|
regression_lags |
scikit-learn |
alpha: 1.0, strategy: "recursive" ("recursive" | "direct"), lags: [1, 2, 3, 7, 14, 28] |
alpha $\in [10^{-2}, 10^{2}]$ (log scale) |
L2-regularized Ridge linear regressor over the lag + calendar + exog design matrix. |
random_forest |
scikit-learn |
n_estimators: 100, max_depth: 10, min_samples_leaf: 2, max_features: 1.0, strategy: "recursive" ("recursive" | "direct"), lags: [1, 2, 3, 7, 14, 28] |
n_estimators $\in [50, 250]$, max_depth $\in [4, 16]$, min_samples_leaf $\in [1, 10]$, max_features $\in {1.0, \text{sqrt}}$ |
Bootstrap-aggregated RandomForestRegressor (n_jobs=1 per worker to prevent executor oversubscription). |
lightgbm |
lightgbm |
n_estimators: 200, learning_rate: 0.05, num_leaves: 31, strategy: "recursive" ("recursive" | "direct"), lags: [1, 2, 3, 7, 14, 28] |
n_estimators $\in [50, 400]$, learning_rate $\in [0.01, 0.2]$, num_leaves $\in [15, 63]$ |
Leaf-wise LGBMRegressor (n_jobs=1 per worker). |
xgboost |
xgboost |
n_estimators: 200, max_depth: 4, learning_rate: 0.05, subsample: 0.8, strategy: "recursive" ("recursive" | "direct"), lags: [1, 2, 3, 7, 14, 28] |
n_estimators $\in [50, 400]$, max_depth $\in [3, 8]$, learning_rate $\in [0.01, 0.2]$, subsample $\in [0.6, 1.0]$ |
Histogram-based XGBRegressor (tree_method="hist"). Supports optional CUDA placement, though CPU is recommended for per-series tabular fits (gpu_usefulness = "suboptimal"). |
catboost |
catboost |
iterations: 200, depth: 6, learning_rate: 0.05, l2_leaf_reg: 3.0, strategy: "recursive" ("recursive" | "direct"), lags: [1, 2, 3, 7, 14, 28] |
iterations $\in [50, 400]$, depth $\in [4, 8]$, learning_rate $\in [0.01, 0.2]$, l2_leaf_reg $\in [1.0, 10.0]$ |
Oblivious (symmetric) decision trees via CatBoostRegressor (thread_count=1, allow_writing_files=False). |
3. Deep learning & open-weight foundation family (deep_learning)¶
Models in the deep_learning family execute on CPU by default and support optional GPU acceleration (gpu_usefulness = "beneficial") across all compute runtimes alongside configurable training_mode (model_params.<model>.training_mode):
"local"(default): Fits or conditions one model per(ts_id, model)cell across Spark, Ray, Vertex CustomJob, GCE, or GKE workers."global": Fits a single shared cross-series network or runs batched panel foundation inference across the entire panel (worker.run_panel_model). Supported by all eightdeep_learningmodels (neuralprophet,tide,tft,tsmixer,patchtst,chronos_bolt,chronos2,timesfm_torch)."hybrid": Supported byneuralprophet, combining global shared AR-Net / seasonality weights with per-series local trend (trend_global_local="local",season_global_local="global").- Separated Optional Extras (
[models-dl]vs.[models-foundation]): Trained neural architectures (neuralprophet,tide,tft,tsmixer,patchtst) belong toscale-forecasting[models-dl], while open-weight pretrained foundation models (chronos_bolt,chronos2,timesfm_torch) belong toscale-forecasting[models-foundation]. Both run on CPU out-of-the-box and leverage GPU tensor cores whencompute.families.deep_learning.use_gpu: true("T4"or"L4").
| Model | Upstream Package | Authored model_params & Defaults |
Optuna search_space |
Covariate Tiers & Notes |
|---|---|---|---|---|
neuralprophet |
neuralprophet |
training_mode: "local" ("local" | "global" | "hybrid"), epochs: 50, learning_rate: 0.01, n_lags: 0, n_forecasts: 1, batch_size: None |
epochs $\in [20, 200]$, learning_rate $\in [10^{-3}, 10^{-1}]$ |
PyTorch AR-Net + piecewise trend + Fourier seasonality with quantile heads ([0.1, 0.5, 0.9]). Univariate local, global, or hybrid panel forecaster (supports_exog = False). |
tide |
neuralforecast |
training_mode: "local" ("local" | "global"), max_steps: 50, input_size: None (auto $2H$), hidden_size: 128, num_encoder_layers: 2, num_decoder_layers: 2, dropout: 0.1, learning_rate: 1e-3, batch_size: 32, scaler_type: "standard" |
max_steps $\in [25, 100]$, hidden_size $\in {64, 128, 256}$, num_encoder_layers $\in [1, 3]$, num_decoder_layers $\in [1, 3]$, dropout $\in [0.0, 0.3]$, learning_rate $\in [10^{-4}, 10^{-2}]$ |
Time-series Dense Encoder (TiDE, Das et al. 2023). Consumes all three covariate tiers (future_covariates, past_covariates, static_covariates) with native MQLoss quantile heads. |
tft |
neuralforecast |
training_mode: "local" ("local" | "global"), max_steps: 50, input_size: None (auto $2H$), hidden_size: 64, n_head: 4, dropout: 0.1, learning_rate: 1e-3, batch_size: 32, scaler_type: "robust" |
max_steps $\in [25, 100]$, hidden_size $\in {32, 64, 128}$, n_head $\in {2, 4, 8}$, dropout $\in [0.0, 0.3]$, learning_rate $\in [10^{-4}, 10^{-2}]$ |
Temporal Fusion Transformer (TFT, Lim et al. 2021). Consumes all three covariate tiers (future_covariates, past_covariates, static_covariates) via gated variable selection networks and multi-head attention. |
tsmixer |
neuralforecast |
training_mode: "local" ("local" | "global"), max_steps: 50, input_size: None (auto $2H$), n_block: 2, ff_dim: 64, dropout: 0.1, learning_rate: 1e-3, batch_size: 32, scaler_type: "standard" |
max_steps $\in [25, 100]$, n_block $\in [1, 4]$, ff_dim $\in {32, 64, 128}$, dropout $\in [0.0, 0.3]$, learning_rate $\in [10^{-4}, 10^{-2}]$ |
All-MLP time- and feature-mixing network (TSMixerx, Chen et al. 2023). Consumes all three covariate tiers (future_covariates, past_covariates, static_covariates). |
patchtst |
neuralforecast |
training_mode: "local" ("local" | "global"), max_steps: 50, input_size: None (auto $2H$), hidden_size: 64, n_heads: 4, encoder_layers: 2, patch_len: 16, stride: 8, dropout: 0.1, learning_rate: 1e-3, batch_size: 32, scaler_type: "standard" |
max_steps $\in [25, 100]$, hidden_size $\in {32, 64, 128}$, n_heads $\in {2, 4, 8}$, patch_len $\in {8, 16, 24}$, dropout $\in [0.0, 0.3]$, learning_rate $\in [10^{-4}, 10^{-2}]$ |
Channel-independent subseries-patch Transformer (PatchTST, Nie et al. 2023) for univariate local or cross-series global forecasting (supports_exog = False). |
chronos_bolt |
chronos-forecasting |
training_mode: "local" ("local" | "global"), size: "base" ("base" | "small" | "mini" | "tiny" or @tiny / @mini / @small tag), context_length: None, batch_size: 256, repo_id: None |
— (zero-shot) | Amazon Chronos-Bolt patch-based T5 foundation model (amazon/chronos-bolt-{size}) with direct multi-step decile heads (0.1..0.9) and process-level LRU checkpoint caching (supports_exog = False). |
chronos2 |
chronos-forecasting |
training_mode: "local" ("local" | "global"), cross_learning: True (default in global mode), context_length: None, batch_size: 256, repo_id: "amazon/chronos-2" |
— (zero-shot) | Amazon Chronos-2 zero-shot foundation model with group attention across future_covariates, past_covariates, and instance-norm-preserving static_covariates carriers (supports_exog = True). |
timesfm_torch |
timesfm |
training_mode: "local" ("local" | "global"), version: "3.0" ("3.0" default | "2.5" or @v2.5 tag), context_length: None (up to 15360), batch_size: 32, ridge: 1.0, repo_id: None |
— (zero-shot) | Open-weight PyTorch Google Research TimesFM 3.0 (google/timesfm-3.0-pytorch with native Variate Attention over future_covariates, past_covariates, and static_covariates) and TimesFM 2.5 (google/timesfm-2.5-200m-pytorch with in-context Ridge covariate regression). |
4. Vertex AI AutoML & Tabular Workflows family (automl)¶
Models in the automl family execute as global cross-series models on runtime = "vertex_automl" via engines/automl_engine.py. By default (automl_mode = "tabular_workflow"), each model compiles and runs a managed Kubeflow Pipelines v2 DAG (google-cloud-pipeline-components) that exports its Stage-1 hyperparameter tuning artifact (stage_1_tuning_result_artifact_uri) to GCS (forecast_metadata.model_artifact) so subsequent runs can warm-start (reuse_tuning_from_run_id) without re-running architecture search. Batch predictions automatically request generate_explanation = True, populating both Tier-1 (forecast_metadata.fit_diagnostics["feature_attributions"]) and Tier-2 (forecast_predictions.explanations) attributions.
| Model | Upstream Package | Pipeline Builder / Training Mode | Authored model_params & Defaults |
Notes |
|---|---|---|---|---|
vertex_l2l |
google-cloud-pipeline-components |
get_learn_to_learn_forecasting_pipeline_and_parameters (tabular_workflow) or AutoMLForecastingTrainingJob (training_job) |
context_window: auto ($2H$), train_budget_milli_node_hours: 1000, optimization_objective: "minimize-wape-mae", stage_1_num_parallel_trials: 8, stage_2_num_selected_trials: 3, reuse_tuning_from_run_id: None |
Vertex AI AutoML / Learn-to-Learn neural architecture search & trial ensembling across all three covariate tiers. |
vertex_tide |
google-cloud-pipeline-components |
get_time_series_dense_encoder_forecasting_pipeline_and_parameters |
context_window: auto ($2H$), train_budget_milli_node_hours: 1000, optimization_objective: "minimize-wape-mae", stage_1_num_parallel_trials: 8, stage_2_num_selected_trials: 3, reuse_tuning_from_run_id: None |
Managed Vertex AI Time-series Dense Encoder (TiDE, Das et al. 2023) Tabular Workflow with reusable Stage-1 HPO and baseline attributions. |
vertex_tft |
google-cloud-pipeline-components |
get_temporal_fusion_transformer_forecasting_pipeline_and_parameters |
context_window: auto ($2H$), train_budget_milli_node_hours: 1000, optimization_objective: "minimize-wape-mae", stage_1_num_parallel_trials: 8, stage_2_num_selected_trials: 3, reuse_tuning_from_run_id: None |
Managed Vertex AI Temporal Fusion Transformer (TFT, Lim et al. 2021) Tabular Workflow with multi-head attention and baseline attributions. |
vertex_seq2seq |
google-cloud-pipeline-components |
get_sequence_to_sequence_forecasting_pipeline_and_parameters |
context_window: auto ($2H$), train_budget_milli_node_hours: 1000, optimization_objective: "minimize-wape-mae", stage_1_num_parallel_trials: 8, stage_2_num_selected_trials: 3, reuse_tuning_from_run_id: None |
Managed Vertex AI Sequence-to-Sequence (Seq2Seq+) encoder-decoder Tabular Workflow across all three covariate tiers. |
5. BigQuery-native SQL family (native)¶
Models in the native family execute directly inside BigQuery via engines/bigquery_engine.py (use_query_cache=False) in parallel with any Spark, Ray, Vertex CustomJob, GCE, GKE, or Vertex AutoML families. Although both models submit the entire panel in a single SQL statement (time_series_id_col = 'ts_id' for arima_plus and id_cols => ['ts_id'] for timesfm), BigQuery partitions by ts_id and forecasts each series independently in isolation (local): arima_plus fits an independent seasonal ARIMA / ARIMA_PLUS_XREG pipeline per ts_id, while timesfm runs zero-shot univariate or multivariate (TimesFM 3.0) inference per ts_id over that series' trailing context_window.
- Flexible
arima_plus&arima_plus_xregConfiguration:"arima_plus"is the canonical model name (list_models()stays at 37 models) and automatically upgrades fromARIMA_PLUStoARIMA_PLUS_XREGwheneverfeatures.future_covariates(exog) is configured. You can also author"arima_plus_xreg"(or"arima_plus@xreg") directly inmodelsandmodel_params: when["arima_plus", "arima_plus_xreg"]are listed together,"arima_plus"is automatically pinned to univariateARIMA_PLUSwhile"arima_plus_xreg"normalizes to"arima_plus@xreg"(ARIMA_PLUS_XREG) for side-by-side Covariate FVA. timesfm&bq_timesfmClarity Alias vs.timesfm_torch: BigQuery's managedAI.FORECASTSQL function is registered as"timesfm"and also accepts"bq_timesfm"(or"bq_timesfm@<tag>") inmodelsandmodel_params, normalizing"bq_timesfm"to"timesfm"with identicalrun_iddigests so configs can explicitly distinguish serverless BigQueryAI.FORECAST(timesfm/bq_timesfm) from open-weight PyTorchtimesfm_torch.- Per-Series
ML.ARIMA_EVALUATE&ML.ARIMA_COEFFICIENTSDiagnostics: After fitting the finalARIMA_PLUS/ARIMA_PLUS_XREGmodel,bigquery_enginequeriesML.ARIMA_EVALUATE(MODEL ..., STRUCT(FALSE AS show_all_candidate_models))andML.ARIMA_COEFFICIENTS(MODEL ...)and records each series' selected(p, d, q)order (non_seasonal_order),has_drift,aic,log_likelihood,variance,seasonal_periods,has_holiday_effect,has_spikes_and_dips,has_step_changes,ar_coefficients,ma_coefficients,intercept_or_drift, and linearxreg_weightsinsideforecast_metadata.fit_diagnostics["arima_diagnostics"]. - In-Database Anomaly & Change-Point Detection (
ForecasterSDK): Both native models support historical anomaly detection viaforecaster.detect_anomalies_df(model_name="arima_plus" | "timesfm", anomaly_prob_threshold=0.95)(ML.DETECT_ANOMALIESforarima_plus/arima_plus@xregandAI.DETECT_ANOMALIESfortimesfm), andarima_plussupports structural regime break detection viaforecaster.detect_change_points_df(model_name="arima_plus")(ML.DETECT_CHANGE_POINTSwith gap-edge artifact filtering).
| Model | Upstream Package | Underlying BigQuery SQL Construct | Authored model_params & Defaults |
Notes |
|---|---|---|---|---|
arima_plus (arima_plus_xreg alias) |
bigquery-ml |
CREATE MODEL ... OPTIONS(model_type='ARIMA_PLUS' \| 'ARIMA_PLUS_XREG') + ML.FORECAST + ML.EXPLAIN_FORECAST + ML.ARIMA_EVALUATE + ML.ARIMA_COEFFICIENTS |
auto_arima_max_order (1..5), auto_arima_min_order (0..5), clean_spikes_and_dips (bool), adjust_step_changes (bool), decompose_time_series (bool), holiday_region (str | list[str]), seasonalities (list of "NO_SEASONALITY", "DAILY", "WEEKLY", "MONTHLY", "QUARTERLY", "YEARLY"), time_series_length_fraction ((0, 1]), min_time_series_length (int >= 1), max_time_series_length (int >= 1), trend_smoothing_window_size (int >= 1) |
Automated per-series seasonal ARIMA pipeline with custom country holiday CTEs (build_custom_holiday_cte), future exogenous covariates (ARIMA_PLUS_XREG), ML.EXPLAIN_FORECAST attributions, and ML.ARIMA_EVALUATE / ML.ARIMA_COEFFICIENTS diagnostics. Rejects forecast_limit_lower_bound / forecast_limit_upper_bound (use output.floor / output.cap instead) and auto_arima=False on multi-series panels. |
timesfm (bq_timesfm alias) |
bigquery-ml |
AI.FORECAST(...) |
version / model: "TimesFM 2.0", "TimesFM 2.5" (univariate default), or "TimesFM 3.0" (shorthand "2.0", "2.5", "3.0", auto-selected when covariates are active); context_window: {64..15360} for 2.0/2.5 or 32n in [64, 2048] for 3.0 |
Zero-shot foundation-model inference per ts_id in SQL with no CREATE MODEL training step. Supports multivariate future_covariates + past_covariates via TimesFM 3.0 (target_cols => ['y']). Validated at plan time (max_horizon <= 10000 for 2.0/2.5; max_horizon <= 1024 for 3.0). |
Two-tier explainability & model-level attribution mechanics¶
scale-forecasting provides two complementary explainability surfaces so forecasters can inspect both feature-level causal attributions (attributions_df / plot_attributions) and structural time-series decomposition (explain_forecast / plot_forecast_explanation):
flowchart LR
subgraph Models["10 Native Attribution Models (supports_explainability = True)"]
ML_MODS["5 Python ML Models (_lag_forecaster.py)<br/>xgboost · lightgbm · catboost<br/>regression_lags · random_forest"]
AML_MODS["4 Vertex AI AutoML Models (automl_engine.py)<br/>vertex_l2l · vertex_tide<br/>vertex_tft · vertex_seq2seq"]
BQ_MODS["1 BigQuery ML Model (bigquery_engine.py)<br/>arima_plus (ML.EXPLAIN_FORECAST)"]
end
subgraph Tier1["Tier 1: Global / Per-Series Driver Importance"]
T1_BQ["forecast_metadata.fit_diagnostics<br/>$.feature_attributions = {feature: importance}"]
end
subgraph Tier2["Tier 2: Per-Horizon-Step Local Attributions"]
T2_BQ["forecast_predictions.explanations<br/>{baseline_score: float, attributions: {feature: signed_delta}}"]
end
subgraph SDK["Unified SDK & Offline Helpers (sdk.py)"]
DF["forecaster.attributions_df(level='both' | 'global' | 'local')<br/>build_attributions_frame(meta_rows, pred_rows)"]
PLT["forecaster.plot_attributions(ts_id, model_type)<br/>2-Panel Global Bar Chart + Horizon-Step Stacked Bar"]
end
ML_MODS & AML_MODS & BQ_MODS --> T1_BQ & T2_BQ
T1_BQ & T2_BQ --> DF --> PLT
Model-level attribution mechanics (supports_explainability = True)¶
All 10 models with native explainability (ml, automl, and arima_plus in native) populate Tier-1 (forecast_metadata.fit_diagnostics["feature_attributions"]) and Tier-2 (forecast_predictions.explanations) attributions automatically:
| Model(s) | Family | Tier 1 (Series / Global Importance) | Tier 2 (Per-Horizon-Step Local Attribution) | Additivity & Baseline Contract |
|---|---|---|---|---|
xgboost |
ml |
Normalized mean $|\phi_{t,j}|$ across training / horizon (feature_importances_ fallback) |
Exact C++ TreeSHAP via Booster.predict(DMatrix, pred_contribs=True) at each recursive or direct step $h \in {1,\dots,H}$ |
Exact: $\hat{y}{T+h}^{\text{raw}} = \text{baseline_score} + \sum_j \phi$ (transformed scale) |
lightgbm |
ml |
Normalized mean $|\phi_{t,j}|$ across horizon (feature_importances_ fallback) |
Exact C++ TreeSHAP via LGBMRegressor.predict(x_step, pred_contrib=True) at each recursive or direct step $h$ |
Exact: $\hat{y}{T+h}^{\text{raw}} = \text{baseline_score} + \sum_j \phi$ |
catboost |
ml |
Normalized mean $|\phi_{t,j}|$ across horizon (get_feature_importance() fallback) |
Exact C++ TreeSHAP via CatBoostRegressor.get_feature_importance(Pool, type="ShapValues") |
Exact: $\hat{y}{T+h}^{\text{raw}} = \text{baseline_score} + \sum_j \phi$ |
regression_lags |
ml |
Normalized $|w_j| \cdot \sigma_{X_j}$ standardized linear weight share | Closed-form linear attribution $\phi_{h,j} = w_j (x_{h,j} - \bar{x}j)$ around $\text{baseline_score} = \bar{y}$} | Exact: $\hat{y}{T+h}^{\text{raw}} = \bar{y}_j)$}} + \sum_j w_j (x_{h,j} - \bar{x |
random_forest |
ml |
Impurity importance feature_importances_ normalized to sum to $1$ |
Importance-weighted directional deviation allocated across active features at step $h$ around $\bar{y}_{\text{train}}$ | Additive: $\hat{y}{T+h}^{\text{raw}} = \bar{y}$}} + \sum_j \phi_{h,j |
vertex_l2l, vertex_tide, vertex_tft, vertex_seq2seq |
automl |
Mean $|\text{attribution}|$ per feature aggregated across each series' horizon steps (or Vertex ModelEvaluation feature attributions) |
Vertex AI Explainable AI (BatchPredictionJob(generate_explanation=True) explanation.attributions baseline_score + feature_attributions) |
Managed Vertex AI baseline-anchored Shapley / Integrated Gradients attribution per (ts_id, forecast_date) |
arima_plus |
native |
Normalized mean $|\text{attribution}|$ across trend, seasonal, holiday_effect, and each attribution_<col> from ML.EXPLAIN_FORECAST |
BigQuery ML.EXPLAIN_FORECAST decomposition (baseline_score = trend + seasonal, attributions = {trend, seasonal, holiday_effect, <xreg_cols>}) |
Additive decomposition of ARIMA_PLUS / ARIMA_PLUS_XREG components per (ts_id, forecast_date) |
All 37 Models (including statistical, deep_learning, native) |
All 5 families | Post-hoc structural decomposition (explain_forecast_frame / forecaster.explain_forecast) |
Decomposes any series' trajectory into Trend, Regime Level Shift, Seasonal Cycle, Exogenous Covariate Alignment, and Conformal Uncertainty Width | Model-agnostic: works identically across univariate statistical, neural, foundation, AutoML, and BigQuery SQL models |
Hierarchical forecasting & coherent reconciliation¶
When hierarchy.enabled: true, the platform aggregates the bottom-level series across hierarchy.levels (including "__total__" at the root), fits base models across all hierarchy nodes, and reconciles base forecasts into coherent hierarchy-wide forecasts $\tilde{y_h} = S G \hat{y_h}$ (reconciliation.py) following Hyndman & Athanasopoulos (Forecasting: Principles and Practice, 3rd ed., Ch. 11) and Wickramasuriya et al. (2019) MinT:
| Reconciliation Method | Matrix $G$ / Weighting $W_h$ | Methodology |
|---|---|---|
bottom_up |
$G = [0 \mid I_{n_b}]$ | Preserves bottom-level forecasts verbatim and sums them upward via the summing matrix $S$. |
top_down |
$G = [p \mid 0]$ | Disaggregates the top-level ("__total__") forecast downward using average historical proportions $p_j = \frac{1}{T}\sum_t y_{j,t} / y_{\text{Total},t}$. |
middle_out |
Disaggregate from middle_level, sum upward |
Preserves base forecasts at hierarchy.middle_level, sums upward to higher levels, and disaggregates downward to bottom series by historical proportions. |
ols |
$W_h = I_n$ | Ordinary least squares MinT projection $G = (S^\top S)^{-1} S^\top$. |
wls_struct |
$W_h = \text{diag}(S \mathbf{1})$ | Structural scaling weighted least squares; requires only the hierarchy structure $S$. |
wls_var |
$W_h = \text{diag}(W_1)$ | Variance scaling weighted least squares using 1-step/OOF residual variances per node. |
mint_shrink |
$W_h = \lambda_D W_{1,D} + (1 - \lambda_D) W_1$ | Wickramasuriya et al. (2019) Minimum Trace optimal reconciliation with analytical Schäfer-Strimmer (2005) shrinkage covariance of residuals; guaranteed positive-definite even when $n_{\text{series}} \gg T_{\text{obs}}$. |
mint_nonneg |
$\min_{\tilde{b} \ge 0} (S\tilde{b} - \hat{y})^\top W_h^{-1} (S\tilde{b} - \hat{y})$ | Non-negative constrained MinT quadratic program (Wickramasuriya, Turlach & Hyndman 2020) solved via scipy.optimize.minimize(method="SLSQP", bounds=[(0, None)]); guarantees $\tilde{y} = S\tilde{b} \ge 0$ at every node while preserving exact hierarchy coherence without post-hoc clipping distortion. |
Post-hoc matrix reconciliation vs. cross-series global models¶
- All 35 Python and Vertex AI AutoML models (
statistical,ml,deep_learning,automl) support all 8 post-hoc reconciliation methods above. - Local per-series models (
training_mode: "local"): Fit each bottom and aggregated upper-level node ("__total__","region=NA","region=NA/category=SMB","s_000000", $\dots$) independently, then apply the reconciliation projection ($\tilde{y_h} = S G \hat{y_h}$ or constrained QP $\tilde{y_h} = S\tilde{b}_h \ge 0$) across both backtest OOF folds and the final horizon forecast. - Global & hybrid panel models (
training_mode: "global"or"hybrid"): Models liketide,tft,tsmixer,patchtst,neuralprophet,chronos_bolt,chronos2,timesfm_torch,vertex_l2l,vertex_tide,vertex_tft, andvertex_seq2seqfit or condition a single shared network simultaneously across all hierarchy levels (and any homogeneousstatic_covariatesinherited by upper-level nodes), learning cross-level interactions inside the network weights during training or batched foundation inference. Because shared neural weights alone do not enforce strict linear additivity ($y_{\text{upper}} = \sum y_{\text{bottom}}$), the platform still applies the configured post-hoc reconciliation projection to both point forecasts and prediction intervals (yhat_lower,yhat_upper), guaranteeing exact coherence across the entire tree. - BigQuery-native models (
arima_plus,timesfm): Execute directly in BigQuery SQL on the source table without driver-side hierarchy rollups (hierarchy.enabled: trueis rejected at preflight fornativemodels with a clearConfigError).
Ensemble blending & stacking strategies¶
When ensemble.enabled: true, the driver combines base-model forecasts into one or more ensemble_<strategy> pseudo-models and writes them to forecast_predictions, backtest_oof, and forecast_metadata alongside the base models:
| Strategy | Type | Requires Backtest | Upstream Package | Methodology |
|---|---|---|---|---|
mean |
Calculated | No | numpy |
Unweighted arithmetic average across all available base models per (ts_id, forecast_date). |
median |
Calculated | No | numpy |
Row-wise median across base models; robust to single-model divergence. |
trimmed_mean |
Calculated | No | numpy |
Symmetric 20% trimmed mean (trim_ratio=0.2) dropping the highest and lowest base predictions at each (ts_id, forecast_date) before averaging when $\ge 3$ models are present. |
inverse_error |
Calculated | Recommended | numpy |
Weighted average with weights $w_m \propto 1 / \text{loss}_m$ under backtest.decision_metric (with optional shrinkage toward uniform $1/K$ via ensemble.weight_shrinkage), normalized to sum to $1$. |
champion |
Calculated Selection | Yes | numpy |
Per-series winner-take-all selector ($w_{m^*} = 1.0$, $0$ elsewhere) picking the single model with the lowest out-of-fold backtest.decision_metric loss on that ts_id. |
horizon_specialist |
Learned Horizon Blending | Yes | numpy |
Partitions the forecast horizon into 3 buckets (short 1..H/3, medium, long) and computes inverse-RMSE weights per (ts_id, bucket) so fast autoregressive models dominate near-term steps and trend/seasonal models dominate long-horizon steps. |
nnls |
Learned Stacking | Yes | scipy |
Non-Negative Least Squares (scipy.optimize.nnls) fit on out-of-fold predictions (w_m >= 0, normalized to sum to $1$, with optional shrinkage toward $1/K$ via ensemble.weight_shrinkage). |
ridge |
Learned Stacking | Yes | numpy |
Closed-form L2-regularized linear meta-learner ($\alpha = 1.0$) fit on the out-of-fold matrix; allows negative corrective weights. |
xgb |
Learned Stacking | Yes | xgboost |
Non-linear gradient-boosted tree meta-learner (XGBRegressor) trained on out-of-fold predictions. |
Environment agility & optional package management¶
All third-party model libraries are imported lazily inside fit() rather than at module import time. This design ensures that:
- Every model registers unconditionally in
scale_forecasting.modelswith zero heavy imports at startup. - Restricted or air-gapped environments that omit specific packages (for example, omitting
catboostorneuralprophet) can still importscale_forecastingand run every other model whose upstream package is installed.
Granular installation extras¶
pyproject.toml layers the install (see runtime_dependencies.md for the whole table): the bare package already fits 15 of the 37 models, and family-scoped extras add the rest so you install only the packages approved for your environment. Each model declares the extra it needs (optional_extra) and the message it raises when that package is missing names it.
| Extra | Installed upstream packages | Models enabled |
|---|---|---|
| (core — no extra) | numpy, scipy, statsmodels>=0.14, scikit-learn>=1.5 |
naive_mean, naive_seasonal, naive_drift, naive_moving_average, croston, regression_lags, fft, theta, holtwinters, autoets, stl_bagging, sarimax, ucm, kalman, random_forest (15) |
scale-forecasting[models-stats] |
statsforecast>=2.0 |
auto_arima, auto_theta, auto_ces, tbats |
scale-forecasting[models-trees] |
xgboost>=2.0, lightgbm>=4.3, catboost>=1.2 |
xgboost, lightgbm, catboost |
scale-forecasting[models-prophet] |
prophet>=1.1.5 |
prophet |
scale-forecasting[models-dl] |
neuralprophet>=0.9, neuralforecast>=1.7, torch>=2.13,<2.14 |
neuralprophet, tide, tft, tsmixer, patchtst |
scale-forecasting[models-foundation] |
chronos-forecasting>=2.2, timesfm[torch]>=3.0 |
chronos_bolt, chronos2, timesfm_torch |
scale-forecasting[models-automl] |
google-cloud-pipeline-components>=2.14 (+ [gcp], which carries google-cloud-aiplatform) |
vertex_l2l, vertex_tide, vertex_tft, vertex_seq2seq |
scale-forecasting[gcp] |
google-cloud-bigquery and the other Google Cloud clients |
arima_plus, timesfm (BigQuery ML runs them; the client submits the SQL) |
scale-forecasting[models] |
The six models-* extras above |
All 37 built-in models (with [gcp] for the two BigQuery ML models) |
Inspecting and filtering available models¶
You can inspect package availability from the CLI or Python SDK, and optionally skip unavailable models when running a shared configuration in a restricted environment:
# List all registered models alongside their upstream package and installation status
uv run python -m scale_forecasting.playground --list
# Run a shared config while automatically skipping any models whose optional package is not installed
uv run python -m scale_forecasting.main --config configs/ensemble_demo.json --ignore-unavailable-models
From Python:
from scale_forecasting.models import filter_available_models, get_model, list_models
from scale_forecasting.playground import model_catalog
# Return only models whose upstream package is importable in the current Python environment
installed = list_models(available_only=True)
# Inspect the full model catalog DataFrame (includes package, package_url, and available columns)
df_catalog = model_catalog()
# Check a single model class directly
cls = get_model("catboost")
print(cls.package, cls.package_url, cls.is_available())
Adding a custom model¶
Adding a new model requires one file in src/scale_forecasting/models/ and one import line in src/scale_forecasting/models/__init__.py:
- Copy
docs/model_template.pytosrc/scale_forecasting/models/my_model.py. - Set
name,family,package,package_url, and implementfit(y, X)andpredict(horizon, X, quantiles). - End the file with
register(MyModel)and importmy_modelinsrc/scale_forecasting/models/__init__.py.
Because src/scale_forecasting is zipped and shipped dynamically on every job submission, your custom model runs on Dataproc Serverless, Dataproc clusters, and Vertex AI Ray immediately with zero container image rebuilds.
See Adding a model (docs/adding_a_model.md) for the full contract and step-by-step walkthrough.