-
Notifications
You must be signed in to change notification settings - Fork 1
Module 6 — Forecasting
File: modules/module6.py · Result: Module6Result
Module 6 turns each scenario's LP allocation into per-KPI forecasts with data-driven confidence bands.
forecast_count = x_{p,g} × (1 / cpu_{p,g,var}) × seasonality_g
For each forecast, the band is selected from this hierarchy:
-
Sample CV when
kpi_observations[var]has ≥3 positive values. This is the actual noise in the data. -
Window-scaled prior —
band = DEFAULT_UNCERTAINTY_BAND × √(REF_WINDOW_DAYS / days). Defaults:DEFAULT_UNCERTAINTY_BAND = 0.30,REF_WINDOW_DAYS = 30. So 90 days → ~17% band; 7 days → ~62% band, floored at 7 days so the band doesn't blow up on thin history. -
Flat default of 0.30 when neither observations nor
historical_daysare available.
Bands are clamped to [_MIN_BAND=0.05, _MAX_BAND=1.00] so the
engine doesn't claim false precision or produce a "forecast ±
200%" that's worse than useless.
This data-driven hierarchy is one of the engine's distinguishing choices — most planning tools either show no uncertainty or a flat "±X%" that has no relation to the input data. Here, more data visibly narrows the band; thin data visibly widens it.
-
Count KPIs (impressions, clicks, leads, etc.) — forecast is
allocation × (1/cpu). Seasonality applies. - Rate KPIs (engagement rate, view rate where present) — forecast is the historical rate, unchanged. No seasonality (rates don't shift with auction cost the way volumes do).
Module 5 multiplies r_{p,g} by the seasonality index before
solving. Module 6 multiplies count-KPI forecasts by the same factor
afterwards. Without the second application, the predicted volume
would diverge from what the LP optimised against; with it,
allocation and forecast stay consistent.