Julian Reder Solo Projects · 2026

NCSU Parking

Campus parking forecast: public occupancy + events into Postgres, a strong seasonal baseline, and per-lot XGBoost only when it beats that baseline.

2026
Private — architecture only
PythonPostgreSQLXGBoostpandasStreamlitDocker
Occupancy API delta snapshots Campus events haversine radius Postgres 5-min grid, lags Hour-of-week median baseline XGBoost kept only if better MAE Streamlit never loads XGBoost 8 horizons 15 min to 24 h, academic-calendar flags
Occupancy + events into Postgres. XGBoost only ships if it beats an hour-of-week median.

Built

A personal forecasting stack for NC State lots. A collector polls the public occupancy API (delta snapshots) and campus events into Postgres; features include 5-minute grids, lags, rolling stats, haversine event radii, and academic-calendar flags. An hour-of-week median is always fit; per-lot XGBoost is kept only if it beats that baseline on validation MAE, across eight horizons from 15 minutes to 24 hours. Training is a separate file-based job so the Streamlit app never loads XGBoost. Private repository — architecture only.

A forecast that can lose

NCSU Parking is a personal stack for campus lots. The public occupancy API and campus events go into Postgres. Features are boring on purpose: 5-minute grids, lags, rolling stats, haversine event radii, academic-calendar flags. Eight horizons, 15 minutes to 24 hours.

Private repository — architecture only. I am not publishing lot-level error tables I cannot stand behind in public.

Baseline first

An hour-of-week median is always fit. Per-lot XGBoost is kept only if it beats that baseline on validation MAE. Most “ML parking” demos skip this gate and then look clever on a Tuesday at 10:00, when the median already knew.

Training is a separate file-based job. The Streamlit app never loads XGBoost. That is not a performance trick. It is how I keep a dashboard from importing a model that failed the gate.

Occupancy API delta snapshots Campus events haversine radius Postgres 5-min grid, lags Hour-of-week median baseline XGBoost kept only if better MAE Streamlit never loads XGBoost 8 horizons 15 min to 24 h, academic-calendar flags
The interesting box is the one that can discard the model.

What the events actually add

A football Saturday is not a residual you invent after the fact. Events are collected with the occupancy, given a radius, and become features. If they do not beat the seasonal median, they do not get to stay either.

The lesson I wanted on the page: a model that is not allowed to lose is not a forecast.