|
Run in Colab Enterprise |
Run in Colab Enterprise: click the badge to import this notebook, pick a runtime, and Run all. The Terraform-deployed templates already carry the
SF_*run identity in their env, so there's no environment cell to fill in. Runs on thesf-mainruntime template (Python 3.11). Seedocs/notebook_runtimes.mdfor the per-notebook template mapping and the headless acceptance harness.
01 · Serverless BigQuery ML Forecasting (ARIMA_PLUS, ARIMA_PLUS_XREG & TimesFM)¶
Execute enterprise time-series forecasting directly inside Google Cloud's serverless data warehouse using pure BigQuery SQL — comparing classical univariate and exogenous state-space decomposition (ML.FORECAST with ARIMA_PLUS and ARIMA_PLUS_XREG + ML.EXPLAIN_FORECAST Two-Tier attributions) against zero-shot foundation model inference (AI.FORECAST with Google Research's TimesFM 2.5 univariate and TimesFM 3.0 multivariate covariates), blending them into a consensus ensemble, and running anomaly, structural change-point, and inventory replenishment diagnostics.
At a glance¶
| Dimension | Details |
|---|---|
| Learning outcomes | Run in-warehouse SQL forecasting (ARIMA_PLUS & ARIMA_PLUS_XREG via ML.FORECAST / ML.EXPLAIN_FORECAST, plus TimesFM 2.5 & TimesFM 3.0 via AI.FORECAST), evaluate 21 metrics + Covariate FVA across rolling-origin folds, inspect Two-Tier ML.EXPLAIN_FORECAST attributions, detect anomalies & structural breaks (detect_anomalies_df, detect_change_points_df), and compute $(s, S)$ inventory replenishment policies (inventory_policy_df). |
| Prerequisites | Deployed scale-forecasting Google Cloud project (SF_* env vars) + scale-forecasting[gcp]. |
| Estimated time | ~3–5 minutes. |
| Estimated run cost | Estimated ~\$0.05–\$0.20 USD (BigQuery query bytes processed / slot-seconds + BigQuery ML model creation & AI.FORECAST inference). |
| Ongoing cost | Zero compute when idle (only standard BigQuery storage for the fitted ARIMA_PLUS / ARIMA_PLUS_XREG models and registry rows; delete anytime with python -m scale_forecasting.registry.ops drop-run <RUN_ID> --yes). |
[!NOTE] Why Both
arima_plus(ARIMA_PLUS/ARIMA_PLUS_XREG) andtimesfm(TimesFM 2.5/3.0) Are Per-Series (local) Models: Even though BigQuery executes all series in a single vectorized SQL query (TIME_SERIES_ID_COL='ts_id'orid_cols=['ts_id']), each series is forecast in mathematical isolation with zero cross-series parameter sharing (supports_global = False). All 21 evaluation metrics are scored by the exact same Python metric engine (metrics.compute_metrics) used by Spark, Ray, Vertex, GCE, and GKE.
flowchart LR
subgraph Source["BigQuery / BigLake Iceberg"]
S1["source_series_covariates_native
or source_series_covariates_iceberg"]
end
subgraph NativeEngine["engines/bigquery_engine.py (Serverless SQL)"]
A1["arima_plus & arima_plus@xreg
CREATE MODEL ... ARIMA_PLUS / ARIMA_PLUS_XREG
+ ML.FORECAST + ML.EXPLAIN_FORECAST"]
T1["timesfm@univariate & timesfm
AI.FORECAST(TimesFM 2.5 & TimesFM 3.0)"]
SCORE["_score_fold()
Identical 21-Metric Panel"]
end
subgraph Ens["ensemble_run.py + Diagnostics"]
E1["combine_calculated() · fit_learned()
mean · inverse_error · nnls · champion
+ FVA · Anomalies · Inventory Policy"]
end
S1 --> A1 & T1 --> SCORE --> E1 --> REG["v_model_leaderboard"]
Act 1 · Cloud Bootstrap & Deployment Resolution¶
On a managed cloud notebook (Colab Enterprise, Vertex AI Workbench) the bootstrap cell below clones or updates the repository and installs the locked dependency set (uv.lock) into an isolated .colab-deps prefix so import scale_forecasting resolves against the exact package versions every cloud worker uses. In a local clone with .venv, this cell is a fast no-op.
# Cloud bootstrap: clone + install the LOCKED dependency set (uv.lock) so
# `import scale_forecasting` resolves against the exact versions every other surface runs.
import importlib.util
import os
import shutil
import subprocess
import sys
REPO_URL = os.environ.get("SF_REPO_URL", "https://github.com/statmike/scale-forecasting.git")
REPO_DIR = os.environ.get("SF_REPO_DIR", "scale-forecasting")
EXTRAS = ['gcp']
if importlib.util.find_spec("scale_forecasting") is None:
if not os.path.isdir(REPO_DIR):
subprocess.run(["git", "clone", "--depth", "1", REPO_URL, REPO_DIR], check=True)
uv = shutil.which("uv")
if uv is None:
subprocess.run([sys.executable, "-m", "pip", "install", "-q", "uv"], check=True)
uv = shutil.which("uv") or "uv"
reqs = os.path.abspath(os.path.join(REPO_DIR, "colab-requirements.txt"))
extra_flags = [f for e in EXTRAS for f in ("--extra", e)]
subprocess.run(
[uv, "export", "--frozen", "--no-emit-project", "--no-hashes", "--no-dev", *extra_flags, "-o", reqs],
cwd=REPO_DIR,
check=True,
)
target = os.path.abspath(os.path.join(REPO_DIR, ".colab-deps"))
subprocess.run(
[uv, "pip", "install", "--python", sys.executable, "--target", target, "-r", reqs],
check=True,
)
sys.path.insert(0, target)
sys.path.insert(0, os.path.join(REPO_DIR, "src"))
print("installed scale_forecasting from", REPO_DIR)
else:
print("scale_forecasting already importable — skipping bootstrap")
scale_forecasting already importable — skipping bootstrap
Resolve the Live GCP Deployment (Settings.resolve())¶
Settings.resolve() reads the SF_* environment variables (SF_PROJECT_ID, SF_REGION, SF_DATASET_ID, SF_WAREHOUSE_URI, SF_CONNECTION, SF_COMPUTE_SA) pre-populated by Terraform in the sf-main runtime template (or your local shell).
from google.cloud import bigquery
from scale_forecasting.settings import Settings
settings = Settings.resolve()
client = bigquery.Client(project=settings.project_id)
DATASET = settings.dataset_ref
print(f"Deployment: {DATASET} | Region: {settings.region} | Bucket: {settings.warehouse_uri}")
Deployment: statmike-scale-forecasting.scale_forecasting | Region: us-central1 | Bucket: gs://statmike-scale-forecasting-warehouse/warehouse
Act 2 · Configure the Native SQL Run & Explain the Execution Plan¶
We configure both BigQuery-native model families with univariate and covariate-enabled variants (arima_plus, arima_plus_xreg, timesfm, timesfm@univariate), known future covariates (promo_flag, price_index), historical past covariates (temperature), a 2-fold rolling-origin backtest, and in-run ensembling (mean, inverse_error, nnls, champion). Calling forecaster.explain() validates the configuration and prints the execution plan before any query is submitted.
import time
from scale_forecasting import Forecaster, RunConfig
# === Parameters — edit me ===============================================
RUN_NAME = f"nb01 bq native {int(time.time())}"
SOURCE_TABLE = "source_series_covariates_native" # flip to "source_series_covariates_iceberg" to read BigLake Iceberg
MODELS = ["arima_plus", "arima_plus_xreg", "timesfm", "timesfm@univariate"]
HORIZON = 28
SERIES_LIMIT = 20
N_FOLDS = 2
ENSEMBLE_STRATEGIES = ["mean", "inverse_error", "nnls", "champion"]
# ========================================================================
cfg = RunConfig(
run_name=RUN_NAME,
data={"source_table": SOURCE_TABLE, "horizon": HORIZON, "series_limit": SERIES_LIMIT},
models=MODELS,
features={
"holidays": ["US"],
"future_covariates": ["promo_flag", "price_index"],
"past_covariates": ["temperature"],
},
backtest={"enabled": True, "n_folds": N_FOLDS, "horizon": HORIZON, "step": HORIZON},
ensemble={"enabled": True, "strategies": ENSEMBLE_STRATEGIES},
)
forecaster = Forecaster(cfg, settings=settings)
print("Deterministic run_id:", forecaster.run_id)
display(forecaster.explain()) # pass validate_data=True to also run BigQuery pre-flight table checks
Deterministic run_id: nb01-bq-native-1792004174-754186bc0ccc
| run_id | family | job_key | runtime | machine_type | workers | hardware | gpu_type | models | training_modes | n_series | n_folds | expected_cells | covariates | depends_on | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | nb01-bq-native-1792004174-754186bc0ccc | native | sf-nb01-bq-native-1792004174-754186bc0ccc-nati... | bigquery | sql | 1 | sql | None | arima_plus, arima_plus@xreg, timesfm, timesfm@... | arima_plus:local, arima_plus@xreg:local, times... | 20 | 2 | 80 | future(2), past(1) | |
| 1 | nb01-bq-native-1792004174-754186bc0ccc | ensemble | sf-nb01-bq-native-1792004174-754186bc0ccc-ense... | bigquery | sql | 1 | sql | None | ensemble_mean, ensemble_inverse_error, ensembl... | barrier | 20 | 2 | 80 | future(2), past(1) | sf-nb01-bq-native-1792004174-754186bc0ccc-nati... |
Act 3 · Launch & Monitor Live (forecaster.run_live())¶
forecaster.run_live() launches forecaster.run() on a background daemon thread, renders a live in-place progress dashboard via forecaster.monitor(), and returns the completed RunResult.
result = forecaster.run_live(poll_s=10.0, probe=True)
print(f"Run {result.run_id} finished with status={result.status} in {result.runtime_seconds:.1f}s")
Run nb01-bq-native-1792004174-754186bc0ccc finished with status=COMPLETED in 305.1s
Act 4 · Retrieve & Review Results (Leaderboard, Distributions & Forecast Fan Charts)¶
With the run complete, we inspect:
forecaster.leaderboard_df(): Ranked model + ensemble table fromv_model_leaderboard.plot_leaderboard()&plot_metric_distribution(): Visual ranking and per-series error quantiles (p10/p50/p90).forecaster.plot_forecasts(): Historical series + backtest OOF overlay + 80% prediction intervals.forecaster.trace()&plot_trace(): Execution timeline across families.
import matplotlib.pyplot as plt
from scale_forecasting import plot_leaderboard, plot_metric_distribution, plot_trace
lb_df = forecaster.leaderboard_df()
display(lb_df)
review = forecaster.review_run()
plot_leaderboard(review)
plt.show()
plot_metric_distribution(review)
plt.show()
| rank | model_type | base_model | family | scope_capability | training_mode | cov_profile | is_univariate | covariates_used | model_spec_hash | ... | mean_mae | mean_rmse | mean_coverage | mean_interval_score | mean_fit_seconds | median_fit_seconds | no_artifact_rate | n_predictions | lift_vs_best_base | lift_pct | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | ensemble_champion | ensemble_champion | ensemble | None | None | None | None | None | None | ... | 11.115575 | 17.742172 | 0.683036 | 65.583338 | None | None | 1.0 | 560 | 0.001996 | 0.005577 |
| 1 | 2 | timesfm | timesfm | native | local_only | local | cov_dynamic | False | promo_flag,price_index,temperature | 30a0ea9f89beebbe | ... | 11.200610 | 18.176520 | 0.799107 | 57.600348 | None | None | 1.0 | 560 | NaN | NaN |
| 2 | 3 | timesfm@univariate | timesfm | native | local_only | local | cov_none | True | d80ff313a6de8f0c | ... | 11.462633 | 18.300876 | 0.770536 | 58.269985 | None | None | 1.0 | 560 | NaN | NaN | |
| 3 | 4 | ensemble_nnls | ensemble_nnls | ensemble | None | None | None | None | None | None | ... | 11.139548 | 17.834735 | 0.669643 | 67.006151 | None | None | 0.0 | 560 | -0.012079 | -0.033755 |
| 4 | 5 | ensemble_inverse_error | ensemble_inverse_error | ensemble | None | None | None | None | None | None | ... | 11.080968 | 17.676197 | 0.668750 | 66.838714 | None | None | 1.0 | 560 | -0.018985 | -0.053054 |
| 5 | 6 | ensemble_mean | ensemble_mean | ensemble | None | None | None | None | None | None | ... | 11.161460 | 17.772690 | 0.670536 | 67.468913 | None | None | 1.0 | 560 | -0.022690 | -0.063408 |
| 6 | 7 | arima_plus@xreg | arima_plus | native | local_only | local | cov_future_only | False | promo_flag,price_index | 8fcf5c3882890e5d | ... | 11.818180 | 18.302014 | 0.605357 | 63.348527 | None | None | 1.0 | 560 | NaN | NaN |
| 7 | 8 | arima_plus | arima_plus | native | local_only | local | cov_none | True | a773fa5348c971a8 | ... | 12.342413 | 18.937531 | 0.591964 | 68.670043 | None | None | 1.0 | 560 | NaN | NaN |
8 rows × 34 columns
# Inspect forecast fan chart + backtest OOF overlay on a single series
preds_df = forecaster.predictions_df(include_history=True, include_oof=True, series_limit=1)
sample_ts = str(preds_df["ts_id"].iloc[0])
print(f"Plotting forecasts for series: {sample_ts}")
forecaster.plot_forecasts(ts_id=sample_ts, history_tail=120)
plt.show()
# Inspect family execution trace
trace_df = forecaster.trace()
display(trace_df)
Plotting forecasts for series: s_000000
| kind | lane | label | start | end | duration_s | status | runtime | model_type | ts_id | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | job | ensemble | ensemble | 2026-10-14 19:00:41.121579+00:00 | 2026-10-14 19:01:04.830874+00:00 | 23.709295 | COMPLETED | bigquery | None | None |
| 1 | job | native | native | 2026-10-14 18:56:47.209878+00:00 | 2026-10-14 19:00:35.098418+00:00 | 227.888540 | COMPLETED | bigquery | None | None |
Act 5 · Deep Dive: 21-Metric Panel, Covariate FVA, ML.EXPLAIN_FORECAST Attributions, Anomalies, Change Points & Inventory Policy¶
- 21-Metric Panel & Covariate FVA (
leaderboard_df(all_metrics=True)&fva_df()): Quantify whether adding exogenous covariates improvedarima_plus@xregover univariatearima_plusandtimesfm(TimesFM 3.0) overtimesfm@univariate(TimesFM 2.5) with Diebold–Mariano $p$-values. - Two-Tier
ML.EXPLAIN_FORECASTAttributions (attributions_df()&plot_attributions()): Inspect Tier 1 global feature importance and Tier 2 per-step forecast attributions (trend,seasonal,holiday_effect,promo_flag,price_index) fromARIMA_PLUS_XREG. - Conformal Interval Calibration & Forecast Decomposition (
plot_calibration()&plot_forecast_explanation()): Compare empirical 80% interval coverage across lead steps $h = 1 \dots H$ and decompose series trajectories. - Universal Anomaly & Structural Change-Point Detection (
detect_anomalies_df()&detect_change_points_df()): Run BigQuery's nativeML.DETECT_ANOMALIES/ML.DETECT_CHANGE_POINTSalongside universal OOF residual segmentation. - Operational Inventory & Replenishment Policy (
inventory_policy_df()&plot_inventory_policy()): Translate calibrated horizon forecasts and backtest residual autocorrelation into per-SKU Reorder Points (ROP), Safety Stock (SS), and recommended order quantities.
full_lb = forecaster.leaderboard_df(all_metrics=True)
display(full_lb)
print("--- Forecast Value Added (Total & Covariate FVA with Diebold-Mariano p-values) ---")
display(forecaster.fva_df())
print("--- Two-Tier ML.EXPLAIN_FORECAST Attributions (arima_plus@xreg) ---")
attr_global = forecaster.attributions_df(model_type="arima_plus@xreg", level="global")
display(attr_global.head(10))
forecaster.plot_attributions(
model_type="arima_plus@xreg",
level="global",
title="Tier 1 Global ML.EXPLAIN_FORECAST Attributions (arima_plus@xreg)",
)
plt.show()
forecaster.plot_attributions(
model_type="arima_plus@xreg",
level="local",
ts_id=sample_ts,
title=f"Tier 2 Per-Step ML.EXPLAIN_FORECAST Attributions ({sample_ts})",
)
plt.show()
display(forecaster.calibration_df(by="horizon").head(10))
forecaster.plot_calibration()
plt.show()
forecaster.plot_forecast_explanation(ts_id=sample_ts, history_tail=120)
plt.show()
print("--- Anomaly & Structural Change-Point Detection ---")
anom_df = forecaster.detect_anomalies_df(model_name="arima_plus@xreg", anomalies_only=True)
display(anom_df.head(10))
cp_df = forecaster.detect_change_points_df()
display(cp_df.head(10))
print("--- Operational Inventory & Replenishment Policy (Continuous Review (s, S) @ 95% CSL) ---")
inv_df = forecaster.inventory_policy_df(
model_name="ensemble_nnls",
lead_time=7.0,
service_level=0.95,
on_hand=150.0,
holding_cost=1.0,
stockout_cost=9.0,
)
display(
inv_df[
[
"ts_id",
"model_type",
"lead_time_demand",
"error_autocorr_rho",
"safety_stock",
"reorder_point",
"recommended_order_qty",
"expected_total_cost",
]
].head(10)
)
forecaster.plot_inventory_policy(
model_name="ensemble_nnls",
lead_time=7.0,
service_level=0.95,
on_hand=150.0,
max_rows=10,
)
plt.show()
| rank | model_type | base_model | family | scope_capability | training_mode | cov_profile | is_univariate | covariates_used | model_spec_hash | ... | mean_rmsle | p50_rmsle | mean_msse | p50_msse | mean_msis | p50_msis | mean_r2 | p50_r2 | mean_cv | p50_cv | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | ensemble_champion | ensemble_champion | ensemble | None | None | None | None | None | None | ... | 0.533580 | 0.318237 | 0.589100 | 0.581731 | 3.823628 | 3.111291 | 0.171807 | 0.032398 | 0.578251 | 0.403684 |
| 1 | 2 | timesfm | timesfm | native | local_only | local | cov_dynamic | False | promo_flag,price_index,temperature | 30a0ea9f89beebbe | ... | 0.539940 | 0.318237 | 0.595496 | 0.586444 | 3.409656 | 2.950583 | 0.166610 | 0.040350 | 0.582706 | 0.403684 |
| 2 | 3 | timesfm@univariate | timesfm | native | local_only | local | cov_none | True | d80ff313a6de8f0c | ... | 0.541491 | 0.313700 | 0.610161 | 0.581731 | 3.454687 | 3.067895 | 0.147739 | 0.027918 | 0.583899 | 0.434743 | |
| 3 | 4 | ensemble_nnls | ensemble_nnls | ensemble | None | None | None | None | None | None | ... | 0.476238 | 0.312247 | 0.573389 | 0.574712 | 3.819906 | 3.133271 | 0.206975 | 0.031070 | 0.556651 | 0.429548 |
| 4 | 5 | ensemble_inverse_error | ensemble_inverse_error | ensemble | None | None | None | None | None | None | ... | 0.472225 | 0.313618 | 0.565727 | 0.523033 | 3.733494 | 3.118753 | 0.227468 | 0.039803 | 0.542148 | 0.423129 |
| 5 | 6 | ensemble_mean | ensemble_mean | ensemble | None | None | None | None | None | None | ... | 0.475904 | 0.313609 | 0.575096 | 0.504452 | 3.797129 | 3.137020 | 0.219137 | -0.010487 | 0.540743 | 0.426203 |
| 6 | 7 | arima_plus@xreg | arima_plus | native | local_only | local | cov_future_only | False | promo_flag,price_index | 8fcf5c3882890e5d | ... | 0.503575 | 0.320699 | 0.616356 | 0.463883 | 3.928701 | 3.501738 | 0.174417 | -0.005486 | 0.534234 | 0.462074 |
| 7 | 8 | arima_plus | arima_plus | native | local_only | local | cov_none | True | a773fa5348c971a8 | ... | 0.515521 | 0.317803 | 0.688080 | 0.462272 | 4.116204 | 3.579147 | 0.107344 | -0.007644 | 0.544433 | 0.468773 |
8 rows × 68 columns
--- Forecast Value Added (Total & Covariate FVA with Diebold-Mariano p-values) ---
| fva_stage_rank | fva_stage | model_type | base_model | demand_class | n_series | n_points | metric | mean_metric | pooled_wape | ... | univariate_baseline_model | covariate_fva_abs | covariate_fva_pct | covariate_p_value_dm | covariate_significant_at_05 | local_baseline_model | pooling_fva_abs | pooling_fva_pct | pooling_p_value_dm | pooling_significant_at_05 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | Baseline | arima_plus | arima_plus | all | 20 | 1120 | wape | 0.408116 | 0.139355 | ... | None | NaN | NaN | NaN | False | None | NaN | NaN | NaN | False |
| 1 | 2 | Statistical / SQL | timesfm | timesfm | all | 20 | 1120 | wape | 0.348967 | 0.126463 | ... | timesfm@univariate | 0.005923 | 0.016691 | 0.001100 | True | None | NaN | NaN | NaN | False |
| 2 | 2 | Statistical / SQL | timesfm@univariate | timesfm | all | 20 | 1120 | wape | 0.354890 | 0.129422 | ... | None | NaN | NaN | NaN | False | None | NaN | NaN | NaN | False |
| 3 | 2 | Statistical / SQL | arima_plus@xreg | arima_plus | all | 20 | 1120 | wape | 0.399999 | 0.133436 | ... | arima_plus | 0.008117 | 0.019889 | 0.243926 | False | None | NaN | NaN | NaN | False |
| 4 | 6 | Ensemble | ensemble_champion | ensemble_champion | all | 20 | 1120 | wape | 0.348443 | 0.125503 | ... | None | NaN | NaN | NaN | False | None | NaN | NaN | NaN | False |
| 5 | 6 | Ensemble | ensemble_nnls | ensemble_nnls | all | 20 | 1120 | wape | 0.361538 | 0.125774 | ... | None | NaN | NaN | NaN | False | None | NaN | NaN | NaN | False |
| 6 | 6 | Ensemble | ensemble_inverse_error | ensemble_inverse_error | all | 20 | 1120 | wape | 0.367915 | 0.125113 | ... | None | NaN | NaN | NaN | False | None | NaN | NaN | NaN | False |
| 7 | 6 | Ensemble | ensemble_mean | ensemble_mean | all | 20 | 1120 | wape | 0.371468 | 0.126021 | ... | None | NaN | NaN | NaN | False | None | NaN | NaN | NaN | False |
8 rows × 30 columns
--- Two-Tier ML.EXPLAIN_FORECAST Attributions (arima_plus@xreg) ---
| ts_id | model_type | compute_engine | feature | importance | |
|---|---|---|---|---|---|
| 0 | s_000000 | arima_plus@xreg | bigquery | price_index | 0.658020 |
| 1 | s_000000 | arima_plus@xreg | bigquery | trend | 0.184002 |
| 2 | s_000000 | arima_plus@xreg | bigquery | seasonal | 0.135954 |
| 3 | s_000000 | arima_plus@xreg | bigquery | holiday_effect | 0.011431 |
| 4 | s_000000 | arima_plus@xreg | bigquery | promo_flag | 0.010593 |
| 5 | s_000001 | arima_plus@xreg | bigquery | price_index | 0.639330 |
| 6 | s_000001 | arima_plus@xreg | bigquery | trend | 0.302129 |
| 7 | s_000001 | arima_plus@xreg | bigquery | holiday_effect | 0.057363 |
| 8 | s_000001 | arima_plus@xreg | bigquery | promo_flag | 0.001178 |
| 9 | s_000002 | arima_plus@xreg | bigquery | trend | 0.799161 |
| model_type | horizon_step | n | coverage | nominal_coverage | coverage_error | mean_width | |
|---|---|---|---|---|---|---|---|
| 0 | arima_plus | 1 | 40 | 0.575 | 0.8 | -0.225 | 17.888902 |
| 1 | arima_plus | 2 | 40 | 0.625 | 0.8 | -0.175 | 20.828999 |
| 2 | arima_plus | 3 | 40 | 0.650 | 0.8 | -0.150 | 22.332859 |
| 3 | arima_plus | 4 | 40 | 0.550 | 0.8 | -0.250 | 23.267542 |
| 4 | arima_plus | 5 | 40 | 0.650 | 0.8 | -0.150 | 23.901164 |
| 5 | arima_plus | 6 | 40 | 0.650 | 0.8 | -0.150 | 24.352030 |
| 6 | arima_plus | 7 | 40 | 0.500 | 0.8 | -0.300 | 24.682402 |
| 7 | arima_plus | 8 | 40 | 0.725 | 0.8 | -0.075 | 24.929076 |
| 8 | arima_plus | 9 | 40 | 0.575 | 0.8 | -0.225 | 25.115641 |
| 9 | arima_plus | 10 | 40 | 0.700 | 0.8 | -0.100 | 25.258098 |
--- Anomaly & Structural Change-Point Detection ---
| ts_id | model_type | ds | y | yhat | lower_bound | upper_bound | anomaly_probability | is_anomaly | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | s_000000 | arima_plus@xreg | 2021-01-02 | 227.510 | 245.665425 | 233.602866 | 257.727984 | 0.996303 | True |
| 1 | s_000000 | arima_plus@xreg | 2021-01-03 | 231.420 | 212.685609 | 200.623050 | 224.748168 | 0.997171 | True |
| 2 | s_000000 | arima_plus@xreg | 2021-02-27 | 232.967 | 248.857665 | 236.795106 | 260.920224 | 0.989714 | True |
| 3 | s_000000 | arima_plus@xreg | 2021-03-17 | 191.745 | 206.155192 | 194.092633 | 218.217751 | 0.980512 | True |
| 4 | s_000000 | arima_plus@xreg | 2021-03-19 | 265.128 | 252.546530 | 240.483971 | 264.609089 | 0.959044 | True |
| 5 | s_000000 | arima_plus@xreg | 2021-03-26 | 263.737 | 280.605971 | 268.543412 | 292.668530 | 0.993353 | True |
| 6 | s_000000 | arima_plus@xreg | 2021-03-27 | 288.160 | 303.659339 | 291.596780 | 315.721898 | 0.987788 | True |
| 7 | s_000000 | arima_plus@xreg | 2021-04-24 | 292.134 | 304.928519 | 292.865960 | 316.991078 | 0.962323 | True |
| 8 | s_000000 | arima_plus@xreg | 2021-05-19 | 152.588 | 139.181926 | 127.119367 | 151.244485 | 0.970488 | True |
| 9 | s_000000 | arima_plus@xreg | 2021-06-17 | 176.599 | 162.310765 | 150.248206 | 174.373324 | 0.979487 | True |
| ts_id | model_type | begin_date | end_date | window_count | window_avg | window_min | window_max | window_stddev | gap_edge_missing_steps | is_gap_edge | status | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | s_000000 | raw | 2021-01-26 | 2021-02-07 | 13 | 188.502769 | 134.928 | 255.680 | 41.357512 | 0 | False | |
| 1 | s_000007 | raw | 2023-08-29 | 2023-09-04 | 7 | 153.746143 | 120.515 | 196.677 | 29.086596 | 0 | False | |
| 2 | s_000008 | raw | 2021-06-06 | 2021-06-25 | 20 | 49.747750 | 31.525 | 79.907 | 14.088549 | 0 | False | |
| 3 | s_000008 | raw | 2022-06-05 | 2022-06-28 | 24 | 74.430000 | 31.660 | 256.688 | 56.878722 | 0 | False | |
| 4 | s_000008 | raw | 2023-06-07 | 2023-06-25 | 19 | 50.390000 | 27.210 | 74.882 | 12.911749 | 0 | False | |
| 5 | s_000008 | raw | 2024-06-08 | 2024-06-26 | 19 | 50.859368 | 30.474 | 66.456 | 10.958760 | 0 | False | |
| 6 | s_000010 | raw | 2024-11-29 | 2024-12-09 | 11 | 134.021909 | 85.212 | 175.438 | 31.012458 | 0 | False | |
| 7 | s_000011 | raw | 2024-11-25 | 2024-12-09 | 15 | 4.795200 | 0.000 | 17.004 | 6.464117 | 0 | False | |
| 8 | s_000013 | raw | 2021-01-22 | 2021-02-05 | 15 | 73.517000 | 62.727 | 86.370 | 6.796223 | 0 | False | |
| 9 | s_000013 | raw | 2023-12-23 | 2024-01-11 | 20 | 93.137300 | 53.347 | 401.212 | 86.065814 | 0 | False |
--- Operational Inventory & Replenishment Policy (Continuous Review (s, S) @ 95% CSL) ---
| ts_id | model_type | lead_time_demand | error_autocorr_rho | safety_stock | reorder_point | recommended_order_qty | expected_total_cost | |
|---|---|---|---|---|---|---|---|---|
| 0 | s_000000 | ensemble_nnls | 1590.134575 | 0.121169 | 87.766272 | 1677.900847 | 1527.900847 | 98.914359 |
| 1 | s_000001 | ensemble_nnls | 5.280125 | 0.135588 | 26.481880 | 31.762006 | 0.000000 | 29.845613 |
| 2 | s_000002 | ensemble_nnls | 1202.268299 | 0.597727 | 114.312882 | 1316.581181 | 1166.581181 | 128.832923 |
| 3 | s_000003 | ensemble_nnls | 541.126591 | 0.411614 | 55.668980 | 596.795571 | 446.795571 | 62.740064 |
| 4 | s_000004 | ensemble_nnls | 381.521922 | 0.676639 | 447.049843 | 828.571765 | 678.571765 | 503.834191 |
| 5 | s_000005 | ensemble_nnls | 1659.825999 | 0.216267 | 44.168800 | 1703.994799 | 1553.994799 | 49.779128 |
| 6 | s_000006 | ensemble_nnls | 3.510889 | -0.031338 | 10.788479 | 14.299368 | 0.000000 | 12.158833 |
| 7 | s_000007 | ensemble_nnls | 1687.643258 | 0.318294 | 131.270191 | 1818.913449 | 1668.913449 | 147.944153 |
| 8 | s_000008 | ensemble_nnls | 370.989202 | -0.053908 | 323.817477 | 694.806679 | 544.806679 | 364.948829 |
| 9 | s_000009 | ensemble_nnls | 470.091226 | 0.806596 | 782.515153 | 1252.606379 | 1102.606379 | 881.910362 |
Where next¶
- Next in Track 2 (Cloud Runtimes):
02_vertex_and_gce_vms.ipynb— run Python models on self-deleting Compute Engine VMs (gce), serverless Vertex AICustomJob(vertex), and GKE Indexed Jobs (gke). - Compare runtimes: Choosing a runtime · Cost estimates & controls
- Documentation: Runtimes reference · Output schemas & views