Prédiction d'Accidents
Big Data & IA
Projet de prédiction d'accidents de la route en France, utilisant des données historiques et des modèles d'apprentissage automatique.
Prédire la gravité d’un accident de la route à partir de variables environnementales (météo, luminosité, état de la chaussée, type de véhicule, heure) sans connaître le comportement des conducteurs impliqués. C’est la contrainte de départ : les données publiques disponibles sont riches en contexte, pauvres en facteurs humains.
Le projet de fin de troisième année couvre l’ensemble du cycle data science : exploration statistique, prétraitement, entraînement de plusieurs familles de modèles, comparaison des performances, et interface web de restitution.
Contexte
Le jeu de données est issu de la base nationale des accidents corporels de la circulation du Ministère de l’Intérieur, millésime 2009. 73 640 enregistrements, avec une cinquantaine de variables : conditions atmosphériques (descr_athmo), luminosité (descr_lum), type de route, configuration de l’intersection, état de la surface, catégorie de véhicule, dispositifs de sécurité présents, âge du conducteur, coordonnées GPS.
La cible de prédiction est la gravité de l’accident : quatre classes : indemne (1), tué (2), blessé hospitalisé (3), blessé léger (4). La classe 1 (indemne) est très majoritaire dans le jeu, ce qui rend le problème non trivial : un classifieur naïf prédisant toujours “indemne” obtient une accuracy correcte sans rien apprendre.
Le projet est réparti en trois parties indépendantes : Big Data (R), IA (Python/Scikit-learn), et Web (PHP/JS).
Objectifs
- Nettoyer et préparer un jeu de données réel avec ses valeurs manquantes, ses encodages hétérogènes et ses déséquilibres de classes.
- Explorer statistiquement les relations entre variables explicatives et gravité (chi², mosaicplots, séries chronologiques).
- Entraîner et comparer plusieurs familles de modèles supervisés : KNN, SVM, Random Forest, MLP.
- Explorer le clustering géographique non supervisé (KMeans) pour identifier des zones à risque.
- Exposer les prédictions dans une interface web avec deux modes : prédiction “haut niveau” par modèle pré-entraîné, et prédiction par cluster géographique.
Architecture
Le projet est organisé en trois dossiers correspondant aux trois parties du cours :
Big Data — R / RStudio
La partie exploration et préparation est entièrement écrite en R. Le fichier preparation.r prend en charge l’encodage des variables catégorielles en valeurs numériques (dictionnaires de recoding issus de la documentation officielle data.gouv.fr), la gestion des valeurs manquantes (remplacement des NULL dans la colonne place par 10, correspondant aux piétons), et la normalisation des colonnes pour produire stat_acc_V3_cleared.csv, le fichier nettoyé transmis à la partie IA.
analyseRelationVar.R produit des tableaux croisés et des tests du chi² entre la variable cible (descr_grav) et chaque variable explicative, visualisés en mosaicplots. analyseRegression.R analyse les tendances temporelles hebdomadaires et mensuelles. graphiques.R et les scripts map*.R génèrent les visualisations cartographiques par département et région, en superposant quantité d’accidents et taux de gravité sur les GeoJSON officiels.
IA — Python / Scikit-learn
La modélisation supervisée est conduite dans AppSupervisé.ipynb. Les features retenues pour l’entraînement sont : age, latitude, longitude, descr_athmo, descr_cat_veh, descr_lum, descr_etat_surf. La variable cible est descr_grav.
La stratégie de validation combine holdout répété (5 splits) et Leave-One-Out sur un sous-échantillon pour l’évaluation du KNN. Pour SVM, RF et MLP, un GridSearchCV sélectionne les hyperparamètres optimaux avant évaluation sur le jeu de test.
La modélisation non supervisée (AppNonSupervisé.ipynb) applique KMeans sur les coordonnées GPS avec n_clusters=5, valeur choisie empiriquement pour capturer la séparation DOM-TOM / nord-sud-centre de la France métropolitaine. Les centroids sont exportés en JSON et utilisés à l’exécution pour affecter un nouveau point à son cluster le plus proche.
Web — PHP / JS
L’interface expose deux modes de prédiction :
- Prédiction haut niveau (
prediction-haut-niveau.html) — l’utilisateur sélectionne un accident existant dans la base, le backend PHP appelleClassWeb.py(chargement du modèle.pklviajoblib, prédiction sur les 7 features) pour chacun des trois modèles (SVM, RF, MLP), et affiche les quatre prédictions en tableau comparatif avecKNeighborsClassifieren quatrième colonne. - Prédiction cluster (
prediction-cluster.html) — l’utilisateur filtre les accidents par critères (ville, âge, date, conditions), le backend retrouve les coordonnées en base, appelleAppNonSupWeb.pyavec les centroids JSON, et retourne le cluster géographique prédit affiché sur une carte Leaflet.
Réalisations
Préparation des données
Le nettoyage a représenté une part conséquente du travail côté R. Les variables catégorielles avaient des libellés textuels longs issus du dictionnaire officiel (ex. "Voiturette (Quadricycle à moteur carrossé) (anciennement \"voiturette ou tricycle à moteur\")") qu’il a fallu recoder en entiers via des dictionnaires recode(). Les valeurs NULL n’étaient pas des NA R standard mais des chaînes de caractères, traitées par boucle.
Résultats des modèles
Les performances mesurées sur le jeu de validation (holdout, 5 splits, 16 % de test) :
- KNN (k=9, distance Manhattan, holdout 5×) — accuracy moyenne : ~54,5 %
- SVM (kernel sigmoid/rbf, GridSearchCV cv=3) — accuracy holdout : ~56,5 %
- Random Forest (n_estimators ∈ {10,100,1000}, max_depth ∈ {None,10,100}, cv=5) — performances comparables au SVM
- MLP (hidden_layer_sizes ∈ {(10,),(100,)}, activation ∈ {relu,tanh}, cv=5) — accuracy holdout moyenne : ~56,1 %
Les performances plafonnent autour de 55-57 %. Ce n’est pas un échec de modélisation : c’est la limite inhérente aux features disponibles. La gravité d’un accident dépend largement de facteurs absents du jeu de données (vitesse au moment de l’impact, délai d’intervention des secours ou encore le non respect des règles de circulation). Les variables environnementales seules n’ont qu’un pouvoir prédictif partiel.
Clustering géographique
KMeans avec 5 clusters sur les coordonnées GPS produit une segmentation géographiquement cohérente : clusters distincts pour les DOM-TOM, le nord, le sud, l’est et l’ouest de la France métropolitaine. Les centroids sont exportés dans centroids.json et utilisés en production pour l’affectation en temps réel.
Stack technique détaillée
R / RStudio : exploration statistique, préparation des données, visualisations (ggplot2, mosaicplot), cartographie (GeoJSON).
Python / Scikit-learn : pipeline de modélisation. KNeighborsClassifier, SVC, RandomForestClassifier, MLPClassifier, GridSearchCV, train_test_split, LeaveOneOut, confusion_matrix.
joblib : sérialisation des modèles entraînés en fichiers .pkl pour rechargement à l’exécution côté web.
PHP : backend web. Routing HTTP manuel, appels shell_exec() vers les scripts Python, requêtes MySQL, sérialisation JSON.
JavaScript / Leaflet : frontend. Carte interactive pour la visualisation des accidents et des clusters, requêtes AJAX vers le backend PHP.
MySQL : persistance du jeu de données nettoyé, requêtes filtrées pour la restitution et la prédiction interactive.
Ce que j’en retire
Ce projet a mis en évidence ce que les tutoriels de machine learning passent généralement sous silence : la modélisation n’est que la dernière étape d’un processus dont la majorité est de la préparation de données.
Le déséquilibre des classes a été la difficulté principale. La tentation de se contenter de l’accuracy globale, qui peut être élevée en ne prédisant jamais les classes rares, est réelle. Voir les matrices de confusion révéler que le modèle prédit massivement la classe 1 (indemne) même avec une accuracy de 56 % a été un moment formateur.
La contrainte des features disponibles a appris quelque chose d’autre : un bon modèle ne peut pas compenser des données structurellement insuffisantes. Comprendre pourquoi les performances plafonnent — et documenter ce plafond honnêtement — est aussi une compétence.
Le couplage PHP/Python par shell_exec() est fonctionnel mais fragile, dépendant du PATH, de la version Python du serveur, et impossible à tester proprement. Un projet plus mature utiliserait une API REST Python (FastAPI) consommée par le frontend. C’est la dette technique évidente que l’on identifie mieux après coup.