Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Traffic Accident Risk Prediction

An end-to-end classification pipeline that scores road conditions as Low / Medium / High accident risk from weather, traffic, road infrastructure and time-of-day features — then tunes its decision threshold to cut false alarms and trains a separate model per season.

Python scikit-learn License

On the data: this project runs on a synthetic 50,000-sample dataset generated inside the script. The features are drawn from realistic distributions (temperature follows a seasonal sinusoid, visibility drops with precipitation and at night, speed falls as volume rises), and the risk label comes from a weighted scoring rule over those features plus Gaussian noise. The pipeline is therefore a demonstration of method, not a validated real-world risk model — the reported scores measure how well the models recover a known generative rule. Swap in real accident records and the same pipeline applies unchanged.


Results

Test set: 10,000 samples held out from 50,000. Best model selected by 5-fold cross-validated F1-macro.

Model CV F1-macro
Logistic Regression 0.7396 ± 0.0081
XGBoost 0.7315 ± 0.0129
Random Forest 0.7120 ± 0.0112

Selected model — Logistic Regression:

Metric Score
Accuracy 0.8609
Precision (macro) 0.7963
Recall (macro) 0.6991
F1 (macro) 0.7348
ROC-AUC (one-vs-rest) 0.9520

Per class:

Class Precision Recall F1 Support
Low 0.68 0.40 0.50 331
Medium 0.88 0.92 0.90 6,738
High 0.83 0.78 0.80 2,931

Confusion matrix

The Low class is the weak point — recall 0.40 on only 331 support. The scoring rule makes genuinely low-risk conditions rare, and the classifier trades them away for accuracy on the two large classes. Class weighting or resampling is the obvious fix and is listed under next steps.

Threshold tuning

Argmax over three classes is not the right operating point when missing a high-risk road costs more than a false alarm. Sweeping the probability threshold for the High class and maximising its F1 gives:

Default (argmax) Tuned (threshold = 0.378)
Accuracy 0.8609 0.8602
Recall (macro) 0.6991 0.7112
F1 (macro) 0.7348 0.7375

Macro recall rises 1.2 points for 0.07 points of accuracy — the trade you want when the cost of a miss is asymmetric.

Seasonal models

Training a dedicated XGBoost per season shows the problem is not uniform across the year:

Season F1-macro
Winter 0.6839
Spring 0.6965
Summer 0.5939
Autumn 0.7254

Summer is hardest: without precipitation and ice as strong signals, the remaining features separate the classes far less cleanly. Every seasonal model scores below the single global model (0.7348), so per-season splitting hurts here — each model sees a quarter of the data and the loss of sample size outweighs the gain in specialisation. That is a useful negative result, not a feature.

Risk by season

Pipeline

Synthetic generator (50,000 samples)
   weather · traffic · road · temporal  ->  weighted risk score + noise -> Low/Medium/High
        |
        v
Feature engineering
   time_of_day (morning/afternoon/evening/night) · is_weekend · volume-to-speed congestion ratio
        |
        v
ColumnTransformer:  OneHotEncoder (categorical) + StandardScaler (numeric)
        |
        v
5-fold CV over {Logistic Regression, Random Forest, XGBoost}  ->  select by F1-macro
        |
        +--> threshold tuning for the High class
        +--> per-season models
        +--> high-risk zone flagging + rule-based prevention suggestions

Quickstart

git clone https://github.com/MrDanial-Rafiee/traffic-accident-risk.git
cd traffic-accident-risk
pip install -r requirements.txt
python traffic_risk.py

The script is deterministic (random_state=42), takes a few minutes on CPU, regenerates every figure into images/, and writes per-sample predictions to predictions.csv.

Features

Group Features
Weather temperature, precipitation, visibility
Traffic traffic_volume, average_speed, volume_speed_ratio
Road road_type, lanes, lighting, signage
Temporal hour, day_of_week, month, season, time_of_day, is_weekend

Prevention suggestions

For each flagged high-risk sample the script emits targeted mitigations from the contributing factors — heavy precipitation triggers a following-distance advisory, poor signage triggers a lane-marking recommendation, winter triggers a gritting recommendation. This is a deliberate rule layer, not a model output: the classifier says how risky, the rules say what to do about it.

Limitations and next steps

  • Synthetic data. The headline scores measure rule recovery, not real-world predictive power. Validating against a real accident dataset is the single most important next step.
  • Low-class recall is 0.40. class_weight='balanced' or SMOTE should be tried before anything else.
  • The GridSearchCV block for XGBoost is written but commented out — it has not been run, so the reported XGBoost score is untuned.
  • No spatial features. Real accident risk is strongly geographic; road segment identity, junction density and historical accident counts per location are all missing.
  • The threshold is tuned on the test set. With real data this needs its own validation split to avoid an optimistic estimate.
  • Seasonal models underperform the global model; a single model with season as a feature (the current global setup) is the better design here.

License

MIT — see LICENSE.

About

Accident risk classification with model comparison, threshold tuning and seasonal models. ROC-AUC 0.952, F1-macro 0.735

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages