Resume-ready time-series demand forecasting portfolio project: retail-style daily unit sales, leak-free validation, strong baselines, gradient boosting / ridge on lag features, and a Streamlit demo recruiters can run locally.
Repo: https://github.com/rohithvairavel-ctrl/demand-forecaster
Store / SKU planners need short-horizon forecasts to set inventory and staffing. Classic ML CV leaks future information on time series — this project uses expanding-window backtests and a chronological holdout.
Primary source (public CSV):
- skforecast simulated item sales — daily demand for 3 items (~2012–2015), retail-like weekly seasonality.
python scripts/download_data.pyA small committed sample lives in data/sample/ so the app/notebooks work offline after clone. If the primary URL is unreachable, the downloader falls back to Prophet’s monthly retail sales example and documents that in data/raw/dataset_meta.json.
- Features: lags (1–28d), rolling mean/std/min/max (7/14/28), calendar + Fourier-style DOW/month encodings.
- Baselines: naive (last value), seasonal naive (weekly).
- Models: Ridge (standardized) and LightGBM on the same supervised frame; recursive multi-step forecasts.
- Validation: expanding-origin backtest (horizon 28, step 28, min train 365) + final chronological holdout.
- Metrics: MAE, RMSE, MAPE, sMAPE.
- Explainability: LightGBM gain / Ridge |coef| feature importance charts.
Expanding-window backtest (horizon 28, 26 folds):
| Model | MAE | RMSE | MAPE |
|---|---|---|---|
| Ridge (best) | 1.44 | 2.13 | 6.37% |
| Seasonal naive | 1.52 | 2.43 | 6.62% |
| LightGBM | 1.52 | 2.29 | 6.85% |
| Naive | 3.09 | 3.82 | 13.24% |
Holdout (last 90 days): Ridge MAE 1.08, MAPE 5.76% — beats seasonal naive (MAE 1.23).
Top drivers: lag_1, lag_2, is_weekend, roll_mean_7, month.
Full numbers in
reports/metrics.json. Re-runpython scripts/train.pyto refresh.
app/streamlit_app.py # interactive demo
scripts/download_data.py # fetch public CSV
scripts/train.py # backtest + fit + figures + models
src/demand_forecaster/ # load, features, models, backtest, metrics
notebooks/01_eda.ipynb
notebooks/02_forecasting.ipynb
reports/metrics.json
reports/figures/*.svg
models/*.joblib(.b64) # artifacts (+ text sidecar for GitHub)
data/sample/ # small committed CSV
git clone https://github.com/rohithvairavel-ctrl/demand-forecaster.git
cd demand-forecaster
python -m venv .venv
# Windows: .venv\Scripts\activate
source .venv/bin/activate
pip install -r requirements.txt
python scripts/download_data.py
python scripts/train.py --series item_1
streamlit run app/streamlit_app.py| Model | Role |
|---|---|
naive |
Last-value baseline |
seasonal_naive |
Weekly seasonal baseline |
ridge |
Linear model on lags + calendar |
lightgbm |
Gradient boosting on same features |
Lower MAE / RMSE / MAPE is better. Prefer models that beat seasonal_naive on the expanding-window leaderboard — that is the bar for “learned something beyond seasonality.”
- Features for day t only use information ≤ t−1 (lags + shifted rolling windows).
- Backtest origins expand forward; each fold retrains from scratch.
- Recursive forecasting feeds predictions back as lags for multi-step horizons.
- Streamlit lets you switch series (
item_1/item_2/item_3), horizon, and model live.
Portfolio / educational use. Dataset © skforecast simulated series (see upstream repo).