Spaces:
Runtime error
Runtime error
| title: BEACON FORECAST | |
| emoji: π | |
| colorFrom: yellow | |
| colorTo: gray | |
| sdk: streamlit | |
| sdk_version: "1.38.0" | |
| python_version: "3.10" | |
| app_file: app.py | |
| pinned: false | |
| # Beacon Forecast β Adaptive Demand Forecaster with Drift Detection | |
| **Portfolio project 5 of 5** β a demo response to the "edge case breakage" | |
| problem retail forecasting faces: rigid models that assume tomorrow looks | |
| like yesterday break when a supply shock, economic shift, or extreme | |
| weather event changes the underlying demand pattern, causing over-stocking | |
| or shortages until someone notices and manually retrains. | |
| > β οΈ **All data in this project is synthetic.** `data/sku_demand.csv` is | |
| > generated by `generate_synthetic_data.py`: 4 SKUs, 2 years of daily data, | |
| > with trend, weekly seasonality, and yearly seasonality. One SKU | |
| > (SKU-004-ELECTRONICS) has an injected supply-shock event at day 500 (a | |
| > sudden ~42% demand drop with a slow, partial 70-day recovery) to exercise | |
| > the drift-detection pipeline. No real Walmart, retailer, or sales data is | |
| > used. | |
| ## Why this exists | |
| A forecaster that's accurate on stable historical data can still be | |
| dangerously wrong the week a real disruption hits, because it keeps | |
| predicting off stale assumptions until someone manually intervenes. This | |
| project closes that loop automatically: the pipeline watches its own | |
| forecast errors day by day, and the moment they drift from what's normal | |
| for that model, it retrains itself on the newest data window without | |
| waiting for a human to notice. | |
| ## Architecture | |
| ``` | |
| daily SKU demand (synthetic, walked forward day by day) | |
| | | |
| v | |
| Forecaster <- forecasting/model.py | |
| trend + weekly seasonality + yearly Fourier terms, fit with Ridge | |
| regression (regularized to stay stable when retrained on short windows -- | |
| a real bug caught during testing: plain OLS produced wildly unstable | |
| trend coefficients that exploded on extrapolation) | |
| | | |
| v | |
| One-step-ahead forecast, day by day | |
| | | |
| v | |
| Drift monitor <- forecasting/drift.py | |
| every 5 days, z-test comparing the last 14 days of forecast error | |
| against the baseline error distribution from right after the last | |
| (re)training; a Kolmogorov-Smirnov test is also computed as a | |
| secondary check on error *shape*, not just mean | |
| | | |
| v | |
| |z| > 4.0 ? ---- no ----> keep current model, keep monitoring | |
| | | |
| yes | |
| v | |
| Automatic retrain on the most recent 120 days | |
| <- stand-in for an Airflow DAG / AWS Lambda retrain trigger | |
| ``` | |
| ## Try it | |
| ```bash | |
| pip install -r requirements.txt | |
| streamlit run app.py | |
| ``` | |
| Pick a SKU in the sidebar. Three tabs: actual vs. forecast over the full | |
| 2-year walk-forward simulation (with retrain events marked), the drift | |
| monitor's z-score history, and a log of every automatic retrain with its | |
| triggering statistics. | |
| Compare **SKU-004-ELECTRONICS** (has the injected shock) against any other | |
| SKU: the shock triggers a retrain within days, with a clearly larger | |
| z-score than routine periodic retrains. The other SKUs also retrain | |
| periodically as ordinary forecast staleness accumulates from a lightweight | |
| linear model β a legitimate, expected MLOps pattern, not just noise: even | |
| without an external shock, a simple model drifts stale over time and | |
| benefits from periodic refitting. | |
| ## Project structure | |
| ``` | |
| demand-forecaster/ | |
| βββ app.py # Streamlit UI | |
| βββ pipeline.py # walk-forward simulation + drift-triggered retraining | |
| βββ generate_synthetic_data.py # produces data/sku_demand.csv | |
| βββ forecasting/ | |
| β βββ model.py # trend + seasonality forecaster (Ridge regression) | |
| β βββ drift.py # z-test + KS-test drift detection | |
| βββ data/ | |
| β βββ sku_demand.csv # SYNTHETIC daily SKU demand, 4 SKUs x 2 years | |
| βββ requirements.txt | |
| ``` | |
| ## Production upgrade path | |
| | Demo component | Production equivalent | | |
| |---|---| | |
| | Trend + Fourier + Ridge regression | Prophet and/or a Temporal Fusion Transformer, per the original architecture brief | | |
| | In-process walk-forward loop | Apache Airflow scheduled runs, containerized with Docker | | |
| | z-test + KS-test on residuals | Evidently AI or Great Expectations for full data-drift reporting (feature drift, not just target/residual drift) | | |
| | Direct in-process retrain | AWS Lambda triggered by the drift-monitoring step, writing a new model version to a registry | | |
| ## Project landing page | |
| `docs/index.html` is a standalone, single-file static landing page (no build step) summarizing the project's results, method, and findings. To host it live on GitHub Pages: repo **Settings β Pages β Source: Deploy from a branch β Branch: main, folder: /docs β Save**. It'll be live within a minute or two at `https://data-geek-astronomy.github.io/BEACON_FORECAST/`. | |