Add privacy-safe demand forecasting case study
Synthetic monthly SKU/region demand notebook comparing a trimmed-mean baseline against gradient boosting, with a gated TimesFM build-vs-buy comparison. Includes rolling-origin validation, executive narrative, architecture diagram, one-page PDF, and LinkedIn draft. No company data, credentials, or private implementation details. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
* text=auto eol=lf
|
||||
*.pdf binary
|
||||
*.png binary
|
||||
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
.venv/
|
||||
.env
|
||||
.ipynb_checkpoints/
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
data/
|
||||
private/
|
||||
51
README.md
Normal file
51
README.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Demand Forecasting Case Study
|
||||
|
||||
Privacy-safe demonstration of a demand-forecasting delivery flow using only synthetic data, written as an executive-readable AI delivery case study.
|
||||
|
||||
## What it demonstrates
|
||||
|
||||
- Monthly demand by synthetic SKU and region.
|
||||
- A baseline forecast: the mean of the preceding eight observed months after removing one minimum and one maximum.
|
||||
- One gradient-boosting model using lag and calendar features.
|
||||
- Leakage-safe rolling-origin validation for a 12-month horizon.
|
||||
- A manual trigger boundary that can later be connected to Airflow.
|
||||
- Annotated charts and written observations connecting modeling choices to delivery governance.
|
||||
- An optional, gated build-vs-buy comparison against a pretrained TimesFM foundation model (`RUN_TIMESFM=1`), evaluating operational cost alongside accuracy instead of switching models by default.
|
||||
|
||||
The notebook calculates evaluation metrics for model selection, but the published case-study narrative intentionally avoids numeric business claims.
|
||||
|
||||
The notebook is structured for an executive audience: it starts with the business question, explains why the baseline exists, visualizes the signal and validation trade-off, and closes with delivery implications for a lean AI task force.
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
uv sync
|
||||
uv run jupyter notebook notebooks/forecasting_case_study.ipynb
|
||||
```
|
||||
|
||||
To execute the notebook non-interactively:
|
||||
|
||||
```bash
|
||||
uv run jupyter execute notebooks/forecasting_case_study.ipynb --inplace
|
||||
```
|
||||
|
||||
To also run the optional TimesFM foundation-model comparison (downloads ~500M-parameter weights
|
||||
from Hugging Face; needs `torch`/`transformers` and internet access):
|
||||
|
||||
```bash
|
||||
RUN_TIMESFM=1 uv run --with torch --with transformers jupyter execute notebooks/forecasting_case_study.ipynb --inplace
|
||||
```
|
||||
|
||||
## Privacy boundary
|
||||
|
||||
This repository contains no company rows, identifiers, schemas, credentials, private URLs, or copied business values. Review `docs/publication-checklist.md` before publishing.
|
||||
|
||||
## Artifacts
|
||||
|
||||
- `notebooks/forecasting_case_study.ipynb` — reproducible analysis.
|
||||
- `docs/architecture.mmd` — editable architecture diagram.
|
||||
- `docs/architecture.svg` — editable/exportable diagram asset used by the handout.
|
||||
- `docs/case-study-one-page.md` — Markdown source for the interview handout.
|
||||
- `docs/case-study-one-page.html` — print-ready handout source.
|
||||
- `docs/case-study-one-page.pdf` — generated one-page interview handout.
|
||||
- `docs/linkedin-post.md` — publication draft.
|
||||
16
docs/architecture.mmd
Normal file
16
docs/architecture.mmd
Normal file
@@ -0,0 +1,16 @@
|
||||
flowchart LR
|
||||
A[Synthetic monthly demand] --> B[Prepare dates and features]
|
||||
B --> C[Trimmed-mean baseline]
|
||||
B --> D[Gradient-boosting model]
|
||||
C --> E[Rolling validation]
|
||||
D --> E
|
||||
E --> F[Select by sMAPE]
|
||||
F --> G[12-month forecast]
|
||||
|
||||
H[Manual trigger today] -.-> B
|
||||
I[Future Airflow boundary] -.-> B
|
||||
|
||||
subgraph Delivery["Delivery ownership"]
|
||||
J[Business question] --> K[Reproducible evidence]
|
||||
K --> L[Review and adoption]
|
||||
end
|
||||
39
docs/architecture.svg
Normal file
39
docs/architecture.svg
Normal file
@@ -0,0 +1,39 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1100" height="430" viewBox="0 0 1100 430" role="img" aria-labelledby="title desc">
|
||||
<title id="title">Demand forecasting delivery architecture</title>
|
||||
<desc id="desc">Synthetic demand flows through preparation, baseline and model, rolling validation, selection, and a twelve-month forecast. Manual triggering today has a future Airflow boundary.</desc>
|
||||
<style>
|
||||
.box { fill: #f5f7fb; stroke: #243b53; stroke-width: 2; rx: 12; }
|
||||
.accent { fill: #d9f0ff; }
|
||||
.text { fill: #102a43; font: 18px sans-serif; text-anchor: middle; }
|
||||
.small { fill: #486581; font: 15px sans-serif; text-anchor: middle; }
|
||||
.arrow { stroke: #486581; stroke-width: 2.5; fill: none; marker-end: url(#arrowhead); }
|
||||
.dashed { stroke-dasharray: 8 7; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
||||
<polygon points="0 0, 10 3.5, 0 7" fill="#486581"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect class="box accent" x="25" y="155" width="155" height="70"/>
|
||||
<text class="text" x="102" y="185">Synthetic</text><text class="text" x="102" y="208">demand</text>
|
||||
<rect class="box" x="220" y="155" width="165" height="70"/>
|
||||
<text class="text" x="302" y="185">Prepare</text><text class="text" x="302" y="208">features</text>
|
||||
<rect class="box" x="425" y="80" width="180" height="70"/>
|
||||
<text class="text" x="515" y="110">Trimmed-mean</text><text class="text" x="515" y="133">baseline</text>
|
||||
<rect class="box" x="425" y="230" width="180" height="70"/>
|
||||
<text class="text" x="515" y="260">Gradient-boosting</text><text class="text" x="515" y="283">model</text>
|
||||
<rect class="box" x="650" y="155" width="175" height="70"/>
|
||||
<text class="text" x="737" y="185">Rolling</text><text class="text" x="737" y="208">validation</text>
|
||||
<rect class="box" x="870" y="155" width="190" height="70"/>
|
||||
<text class="text" x="965" y="185">12-month</text><text class="text" x="965" y="208">forecast</text>
|
||||
<path class="arrow" d="M180 190 H220"/>
|
||||
<path class="arrow" d="M385 190 H410 V115 H425"/>
|
||||
<path class="arrow" d="M385 190 H410 V265 H425"/>
|
||||
<path class="arrow" d="M605 115 H625 V190 H650"/>
|
||||
<path class="arrow" d="M605 265 H625 V190 H650"/>
|
||||
<path class="arrow" d="M825 190 H870"/>
|
||||
<text class="small" x="300" y="45">Manual trigger today</text>
|
||||
<path class="arrow dashed" d="M300 55 V145"/>
|
||||
<text class="small" x="740" y="365">Future orchestration boundary</text>
|
||||
<path class="arrow dashed" d="M740 350 V235"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
55
docs/case-study-one-page.html
Normal file
55
docs/case-study-one-page.html
Normal file
@@ -0,0 +1,55 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Demand Forecasting Case Study</title>
|
||||
<style>
|
||||
@page { size: A4; margin: 14mm; }
|
||||
body { color: #102a43; font: 10.5pt Arial, sans-serif; line-height: 1.35; margin: 0; }
|
||||
h1 { color: #0b4f71; font-size: 24pt; margin: 0 0 4pt; }
|
||||
h2 { color: #0b4f71; font-size: 13pt; margin: 10pt 0 3pt; }
|
||||
p { margin: 4pt 0; }
|
||||
.subtitle { color: #486581; font-size: 11pt; margin-bottom: 8pt; }
|
||||
.card { background: #f5f7fb; border-left: 4px solid #2f80a8; padding: 7pt 9pt; }
|
||||
img { display: block; margin: 5pt auto; max-width: 100%; }
|
||||
.columns { display: grid; grid-template-columns: 1fr 1fr; gap: 12pt; }
|
||||
ul { margin: 4pt 0 0 16pt; padding: 0; }
|
||||
li { margin: 2pt 0; }
|
||||
footer { border-top: 1px solid #bcccdc; color: #627d98; font-size: 8.5pt; margin-top: 9pt; padding-top: 5pt; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>From demand question to forecast evidence</h1>
|
||||
<div class="subtitle">A privacy-safe, player/coach delivery case study using synthetic monthly demand</div>
|
||||
<div class="card">
|
||||
<strong>The case.</strong> Build a repeatable forecasting flow without exposing operational data.
|
||||
The public version preserves the delivery decisions that matter: preparation, an auditable
|
||||
baseline, model comparison, validation, and a clear operating boundary.
|
||||
</div>
|
||||
<h2>Architecture</h2>
|
||||
<img src="architecture.svg" alt="Demand forecasting delivery architecture">
|
||||
<div class="columns">
|
||||
<div>
|
||||
<h2>Modeling choices</h2>
|
||||
<ul>
|
||||
<li>Monthly demand by synthetic SKU and region.</li>
|
||||
<li>Baseline: previous eight months, excluding one minimum and one maximum.</li>
|
||||
<li>One gradient-boosting model with lag and calendar features.</li>
|
||||
<li>Rolling-origin validation for a 12-month horizon.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Delivery choices</h2>
|
||||
<ul>
|
||||
<li>Start with a baseline stakeholders can audit.</li>
|
||||
<li>Add complexity only when validation earns it.</li>
|
||||
<li>Keep triggering manual while the workflow is proved.</li>
|
||||
<li>Leave a clean seam for future orchestration.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Evidence</h2>
|
||||
<p>The notebook computes validation metrics and produces comparison charts. This handout makes no numeric business claims because the data is synthetic.</p>
|
||||
<footer>Public-safe artifact: no company rows, identifiers, credentials, private URLs, or copied business values.</footer>
|
||||
</body>
|
||||
</html>
|
||||
25
docs/case-study-one-page.md
Normal file
25
docs/case-study-one-page.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# From demand question to forecast evidence
|
||||
|
||||
## The case
|
||||
|
||||
Build a repeatable forecasting flow without exposing operational data. The public version uses synthetic monthly demand by SKU and region while preserving the delivery decisions that matter: data preparation, a transparent baseline, model comparison, validation, and a clear operating boundary.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
source[Synthetic demand] --> prep[Preparation/features]
|
||||
prep --> baseline[Trimmed-mean baseline]
|
||||
prep --> model[Gradient boosting]
|
||||
baseline --> validate[Rolling validation]
|
||||
model --> validate
|
||||
validate --> forecast[12-month forecast]
|
||||
```
|
||||
|
||||
## Delivery narrative
|
||||
|
||||
Start with a baseline that stakeholders can audit. Add one model only when validation shows a useful improvement. Keep the trigger manual while the workflow is being proved, then expose the same boundary to an orchestrator such as Airflow.
|
||||
|
||||
## Evidence
|
||||
|
||||
The notebook computes validation metrics and produces comparison charts. This handout deliberately makes no numeric business claims because the data is synthetic.
|
||||
BIN
docs/case-study-one-page.pdf
Normal file
BIN
docs/case-study-one-page.pdf
Normal file
Binary file not shown.
13
docs/linkedin-post.md
Normal file
13
docs/linkedin-post.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# LinkedIn draft
|
||||
|
||||
I built a privacy-safe demand-forecasting case study to show how I approach AI delivery as a player/coach.
|
||||
|
||||
The demo starts with synthetic monthly demand by SKU and region, then compares:
|
||||
|
||||
- an auditable baseline based on the previous eight months;
|
||||
- one gradient-boosting model with lag and calendar features;
|
||||
- rolling time-based validation instead of a random train/test split.
|
||||
|
||||
The important part is not adding the most models. It is making the path from business question to reproducible evidence explicit: prepare the data, establish a baseline, validate the model, document the operating boundary, and leave a clean seam for future orchestration.
|
||||
|
||||
The public repository contains no company data or private implementation details.
|
||||
9
docs/publication-checklist.md
Normal file
9
docs/publication-checklist.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Publication checklist
|
||||
|
||||
- [ ] No credentials, tokens, private keys, `.env` files, or secret names.
|
||||
- [ ] No company rows, identifiers, product names, plant names, or business values.
|
||||
- [ ] No private schemas, endpoints, account names, or internal URLs.
|
||||
- [ ] All charts and metrics come from synthetic data.
|
||||
- [ ] Numeric results are labeled illustrative and are not presented as business outcomes.
|
||||
- [ ] Notebook executes from a clean environment with `uv`.
|
||||
- [ ] Diagram and PDF contain only generic architecture terms.
|
||||
654
notebooks/forecasting_case_study.ipynb
Normal file
654
notebooks/forecasting_case_study.ipynb
Normal file
File diff suppressed because one or more lines are too long
16
pyproject.toml
Normal file
16
pyproject.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[project]
|
||||
name = "ml-forecasting-case-study"
|
||||
version = "0.1.0"
|
||||
description = "Privacy-safe demand forecasting case study"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"jupyter",
|
||||
"matplotlib",
|
||||
"nbclient",
|
||||
"numpy",
|
||||
"pandas",
|
||||
"scikit-learn",
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
package = false
|
||||
Reference in New Issue
Block a user