Schema — forecast¶
Tables an experiment of type=forecast publishes. The forecast fact is tidy
and keyed on (series, ts) — there is no row_index and no positional join
to inputs.
Contents¶
- Fact:
*__forecast - Example queries
Fact — *__forecast (PK (series, ts))¶
| column | notes |
|---|---|
series |
series identifier (key) |
ts |
timestamp of the forecast point — a string; cast when range-filtering |
yhat |
point forecast |
model |
the series' winning model (its CV winner) |
yhat_lower_<level>? |
lower bound at <level>% — one pair per level the run produced (yhat_lower_80, yhat_lower_95, …); NULL where the series' winner carries no band at that level |
yhat_upper_<level>? |
upper bound at <level>% |
One row per (series, ts), so SUM(yhat) counts each point once. Whether a
level is calibrated is on the run's forecast diagnostics (get_insight), not in
this table. Never join a forecast on row_index. Aggregate/compare per series
and ts.
Example queries¶
Placeholder <forecast> is the data-kb name.
One series, full horizon with its 80% and 95% bands (read the level columns off the catalog first):
SELECT ts, yhat, yhat_lower_80, yhat_upper_80, yhat_lower_95, yhat_upper_95
FROM "<forecast>" WHERE series = 'store_42' ORDER BY ts;
Total predicted demand per series:
SELECT series, SUM(yhat) AS total_yhat
FROM "<forecast>" GROUP BY series ORDER BY total_yhat DESC;
Widest 80% prediction intervals:
SELECT series, ts, (yhat_upper_80 - yhat_lower_80) AS interval_width
FROM "<forecast>"
ORDER BY interval_width DESC LIMIT 20;
Range filter (cast the string ts):
SELECT series, ts, yhat
FROM "<forecast>"
WHERE CAST(ts AS TIMESTAMP) >= TIMESTAMP '2026-01-01'
ORDER BY series, ts;