BEACON_FORECAST / README.md
Darkweb007's picture
Fix emoji field for HF Space validation
d31f070
|
Raw
History Blame Contribute Delete
4.89 kB
---
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/`.