Skip to content

Repository files navigation

AccidPre

Monthly traffic-accident forecasting for the city of Munich, served as a REST API.

AccidPre turns the City of Munich's open "Monatszahlen Verkehrsunfälle" dataset into a set of per-category time-series forecasters. Seven NeuralProphet models — one for every combination of accident category and accident type present in the data — are trained offline with a hyper-parameter grid search, exported as artifacts, and exposed through a small FastAPI service that answers "how many accidents are expected in month M of year Y?".


Overview

The City of Munich publishes monthly accident counts broken down by category (MONATSZAHL) and type (AUSPRAEGUNG); the raw file bundled in data/ covers monthly observations from January 2000 onwards. AccidPre does three things:

  1. Prepare – the raw CSV is cleaned(rows without a value are dropped), the MONAT column is parsed from YYYYMM into a real timestamp, and the frame is split into one univariate series per (category, type) pair in the NeuralProphet ds/y format.
  2. Train – every series is fitted with NeuralProphet using an exhaustive grid search over learning rate, normalisation, batch size and yearly seasonality, with German public holidays as an extra regressor. The best configuration per series is refitted and persisted.
  3. Serve – a FastAPI app loads the matching model artifact, extends the historic frame to the requested month and returns the rounded point forecast (yhat1).

Features

  • 📈 Seven independent monthly forecasters, one per accident category/type combination.
  • 🇩🇪 German public holidays added to every model via add_country_holidays(country_name='DE').
  • 🔎 Full grid search (72 configurations per series) with train / validation / test splits and MAE + RMSE logged for every configuration.
  • ⚡ Historical months are answered straight from the prepared CSVs — no model inference needed.
  • 🌐 Typed request/response contract via Pydantic, plus a health-check route.

Architecture

flowchart LR
    A["monatszahlen2307_verkehrsunfaelle<br/>_10_07_23_nosum.csv"] --> B["accid_predictor_train.py<br/>clean · parse dates · group"]
    B --> C["data/data_&lt;cat&gt;_&lt;type&gt;.csv<br/>ds, y (2000-01 … 2020-12)"]
    B --> D["Grid search<br/>NeuralProphet + DE holidays"]
    D --> E["models/neuralprophet/<br/>model_&lt;cat&gt;_&lt;type&gt;.np / .pkl"]
    D --> F["train_log/neuralprophet/<br/>train.log · loss curves"]

    G["POST /predict<br/>{year, month}"] --> H["app/app.py<br/>FastAPI + Pydantic"]
    H --> I["accid_predictor.predict_accid()"]
    I --> J{"requested month"}
    J -->|"before 2000-01"| K["-1"]
    J -->|"2000-01 … 2020-12"| C
    J -->|"after 2020-12"| E
    E --> L["make_future_dataframe → predict<br/>round(yhat1)"]
    C --> L
    K --> M["{prediction: int}"]
    L --> M
Loading

Tech Stack

Layer Technology
Forecasting NeuralProphet (PyTorch Lightning backend)
Data wrangling pandas, NumPy
Visualisation Matplotlib, seaborn, plotly-static
API FastAPI, Pydantic
ASGI server Uvicorn
Reverse proxy nginx (restarted by app/start.sh)
Experiment tracking Python loggingtrain_log/neuralprophet/train.log

Data

Source: Monatszahlen Verkehrsunfälle, München Open Data Portal (file data/monatszahlen2307_verkehrsunfaelle_10_07_23_nosum.csv).

Relevant raw columns: MONATSZAHL, AUSPRAEGUNG, JAHR, MONAT, WERT.

Series file MONATSZAHL AUSPRAEGUNG
data_alk_ins.csv Alkoholunfälle insgesamt
data_alk_vug.csv Alkoholunfälle Verletzte und Getötete
data_flu_ins.csv Fluchtunfälle insgesamt
data_flu_vug.csv Fluchtunfälle Verletzte und Getötete
data_ver_ins.csv Verkehrsunfälle insgesamt
data_ver_mps.csv Verkehrsunfälle mit Personenschäden
data_ver_vug.csv Verkehrsunfälle Verletzte und Getötete

Split convention used during training: everything before 2021-01-01 is train + validation (15 % held out for validation via NeuralProphet.split_df), everything from 2021-01-01 onwards is the test set.

Getting Started

Prerequisites

  • Python 3.x
  • The trained artifacts in models/neuralprophet/ and the prepared series in data/ (both are committed in this repository); optionally nginx, to run the deployment script as-is

Installation

git clone https://github.com/NingyueZhou/AccidPre.git
cd AccidPre
pip install -r app/requirements.txt

app/requirements.txt covers the serving side only (uvicorn, fastapi, pydantic, pandas). Retraining additionally needs neuralprophet, numpy, matplotlib and seaborn.

Run the API

The predictor resolves ../data/... and ../models/... relative to the working directory, so the server must be started from inside app/:

cd app
python app.py

This binds Uvicorn to 127.0.0.1:4343. For a reload-enabled dev server use uvicorn app:app --reload from the same directory.

Deployment

app/start.sh is the production entry point used behind a reverse proxy:

./app/start.sh

It restarts nginx and then launches Uvicorn on 0.0.0.0 with --proxy-headers and --forwarded-allow-ips='*' so client IPs survive the proxy hop.

Retraining

python accid_predictor_train.py

The script rebuilds the per-series CSVs in data/, runs the grid search, writes loss curves and per-configuration metrics to train_log/neuralprophet/, and dumps the best model per series into models/neuralprophet/. accid_predictor_train.ipynb contains the same pipeline in notebook form with the exploratory plots.

Usage

Health check — curl http://127.0.0.1:4343/ returns {"Heathcheck": "OK"}.

Prediction— the body matches app/sample_request.json:

curl -X POST http://127.0.0.1:4343/predict \
  -H "Content-Type: application/json" \
  -d @sample_request.json

Request:

{
  "year": 2020,
  "month": 10
}

Response:

Response — October 2020 lies inside the historic range, so the value is read straight from data/data_alk_ins.csv (which records 2020-10-01,34.0):

{
  "prediction": 34
}

Semantics of the returned value:

Requested month Behaviour
before 2000-01 returns -1 (outside the data range)
2000-01 … 2020-12 historic value looked up in the prepared CSV
after 2020-12 NeuralProphet forecast, rounded to the nearest integer

Interactive OpenAPI docs are available at http://127.0.0.1:4343/docs.

Project Structure

AccidPre/
├── accid_predictor_train.py        # data prep + grid search + model export
├── accid_predictor_train.ipynb     # same pipeline with exploratory plots
├── app/
│   ├── app.py                      # FastAPI app: GET / and POST /predict
│   ├── accid_predictor.py          # model loading, period math, prediction
│   ├── sample_request.json         # example payload
│   ├── requirements.txt            # serving dependencies
│   └── start.sh                    # nginx + uvicorn deployment script
├── data/
│   ├── monatszahlen2307_verkehrsunfaelle_10_07_23_nosum.csv
│   └── data_<category>_<type>.csv  # 7 prepared ds/y series
├── models/neuralprophet/
│   └── model_<category>_<type>.np|.pkl
└── train_log/neuralprophet/
    ├── train.log                   # metrics for every grid-search run
    ├── data_<series>.png           # series plots
    └── loss_<series>.png           # train/validation loss curves

Results

Grid search performed per series (accid_predictor_train.py):

Hyper-parameter Values searched
learning_rate 0.001, 0.008, 0.01, 0.1
normalize minmax, soft, standardize
epochs 300
batch_size 3, 6, 12
yearly_seasonality True, False

That is 72 configurations per series, ranked by test RMSE; the best-ranked configuration is refitted and saved. Per-configuration MAE and RMSE for train, validation and test are recorded in train_log/neuralprophet/train.log, and the corresponding loss curves are stored alongside it.

Limitations

  • The /predict endpoint only accepts year and month; the category and type are fixed to the defaults of predict_accid (category='alk', type='ins'). The other six models are trained and shipped but not reachable through the HTTP API yet.
  • Model artifacts are frozen at the 2020-12 cut-off, so long-horizon requests extrapolate far beyond the last observed month.
  • Relative paths (../data, ../models) require the server to run with app/ as the working directory.
  • No authentication, rate limiting or input upper bound on year.

Acknowledgements

  • Digital Product School for setting this challenge for aspiring AI engineers.
  • München Open Data Portal for publishing the Monatszahlen Verkehrsunfälle dataset.
  • The NeuralProphet project for the forecasting library.

License

No license file is present in this repository.

About

An AI application predicting the number of accidents in Munich for a specific category and datetime.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages