À la découverte de l’API du métro parisien : 7 jours d’observation des messages info trafic
Dans mon article précédent, j’expliquais comment trouver le trajet le plus pratique entre 2 stations du métro parisien. Connaître le bon chemin, c’est bien. Savoir si la ligne est fiable, c’est encore un autre sujet, malheureusement d’actualité.
Cela m’a donné l’idée d’observer pendant quelques jours, les incidents remontant du métro parisien en interrogeant les données disponibles. Ancien apprenant du cursus DataScientest, je vais vous montrer dans cet article comment interroger une API et récupérer les données qu’elle renvoie.
Le Portail Régional d’Information pour la Mobilité (PRIM), créé par l’organisme Île-de-France Mobilités, a pour but de mettre à disposition du public des données en Open Data. Parmi celles-ci, une API permet de connaître en temps réel les perturbations affectant la circulation des métros parisiens.
Qu’est ce qu’une API ?
Une API, pour Application Programming Interface, est un programme permettant à deux applications distinctes de communiquer entre elles et d’échanger des données. Cela évite notamment de recréer et redévelopper entièrement une application pour y ajouter ses informations. Par exemple, elle est là pour faire le lien entre des données déjà existantes et un programme indépendant.
(extrait d’un article de DataScientest sur les API)
J’ai ainsi créé un script python tournant sur mon Raspberry Pi et destiné à interroger l’API “Messages Info Trafic”. Celle-ci met à disposition en temps réel les messages info trafic disponibles dans les réseaux de transport franciliens. Pour l’interroger, il faut préciser la ligne concernée, le type d’information (commerciales ou perturbations) ainsi que son token d’authentification (on peut en obtenir un gratuitement en s’inscrivant sur le site web du PRIM). En raison du quota de requêtes gratuites, j’ai prévu d’interroger l’API toutes les 15 minutes pendant 7 jours en laissant de côté les 2 lignes bis du métro.
En premier lieu, j’ai crée un dataframe destiné à stocker les données récupérées :
Celui-ci contient un champ timecode qui me permet de connaître le moment où les données ont été récupérées. Les champs ligne et statut permettent respectivement de stocker la ligne de métro concernée et de savoir si tout va bien ou s’il y a des perturbations.
L’interrogation de l’API en elle-même prend relativement peu de lignes. Les informations sur les modalités d’interrogations sont documentées sur le site du PRIM.
Comme son nom l’indique, la variable url précise l’url de la requête qui contient le code de la ligne concernée (code_ligne) et les informations à récupérer, dans notre cas, les perturbations. Le référentiel des lignes et des codes correspondants est également disponible dans la documentation du PRIM.
La variable header précise quant à elle la façon dont je veux récupérer les données (en JSON ici). C’est également là que je fournis à l’API mon token d’authentification.
Enfin, la dernière ligne permet de lancer la fameuse requête en fonction des paramètres précisés dans les 2 lignes précédentes.
Une fois la requête lancée, il s’agit maintenant de récupérer les informations utiles. Dans le fichier JSON que je reçois, il y a beaucoup de données qui ne m’intéressent pas. Ce que je veux uniquement, c’est récupérer les messages d’info trafic.
C’est cette partie du code qui traite la prise en charge des données :
Lorsque une requête est reçue, l’API indique en retour si celle-ci a réussie (status 200) ou s’il y a eu un problème quelconque (généralement status 4XX). Ainsi, le traitement des données ne se lance que si la requête a été correctement traitée.
Les données JSON arrivent sous forme « byte ». Le script doit donc les convertir en un dictionnaire susceptible d’être parcouru et traité. C’est le rôle des lignes 3 et 4.
Les messages d’information sont contenus dans cette partie du fichier JSON :
[“Siri”][“ServiceDelivery”][“GeneralMessageDelivery”][0][‘InfoMessage’].
En cas d’absence de message, cette partie est vide. Si elle ne l’est pas, les lignes 6 à 10 du code parcourent la partie [infoMessage] du fichier au moyen d’une boucle afin d’extraire les messages et de les ajouter dans le dataframe avec la ligne du métro correspondante ainsi que le timecode.
Au cas où aucun problème n’est remonté, les 3 dernières lignes du code prévoient l’insertion d’un message « tout va bien » indiquant également le timecode et la ligne. Cela permettra par la suite de vérifier que les données ont été bien renvoyées par l’API pendant la période d’observation.
J’obtiens à ce stade un script qui permet d’interroger l’API. En revanche, il ne traite qu’une seule ligne. Il faut donc créer une boucle pour pouvoir interroger la situation des 14 lignes que nous observons.
Par ailleurs, mon script n’est pas protégé en cas de problème de connexion. Si jamais je perdais ma connexion internet pendant une tentative de requête sur l’API, Python générerait un message d’erreur qui arrêterait l’exécution du script. J’ajoute donc également une prise en charge de ce type d’erreur grâce aux clauses try et except.
Toujours par souci de sécurité, le dataframe mis à jour est exporté en csv quand la boucle a parcouru l’ensemble des lignes.
J’encapsule alors le tout dans une fonction nommée requête_ligne. Celle-ci devant être appelée toutes les 15 minutes. La fonction ainsi créée est disponible ici avec le code complet du script.
Pour finir, la dernière partie du script lance les requêtes toutes les 15 minutes.
Je crée une boucle infinie qui fait tourner indéfiniment le script jusqu’ à ce que je l’interrompe moi-même. C’est pourquoi j’indique au tout début l’heure de lancement, afin d’éviter d’arrêter le script à un moment où il serait susceptible de lancer un requêtage sur l’API.
Le requêtage est lancé toutes les 15 minutes grâce à time.sleep (vous noterez que 15 minutes équivalent à 900 secondes, mais j’intègre le temps d’exécution du requêtage, ce qui explique le délai moins élevé.
Enfin, le nombre de requêtes gratuites par jour étant limité, j’ajoute une condition liée à l’heure afin de ne pas interroger l’API quand le métro ne circule pas.
Une fois le script prêt, je l’ai lancé sur mon Raspberry Pi puis laissé tourner pendant 7 jours du 6 au 13 janvier en ne tenant pas compte des deux jours de week-end (quand les lignes sont moins sollicitées).
Analyse des données obtenues
Une fois la période d’observation écoulée, j’ai récupéré le fichier csv pour analyse. J’ai pu constater qu’il n’y avait pas eu d’interruption dans l’alimentation des données. J’ai également enlevé certains messages, déjà repérés en amont lors de mes tests de script, qui concernaient des perturbations liées à des travaux. Celles-ci, prévues à l’avance, n’avaient pas à être prises en compte. Je précise également qu’aucun mouvement de grève n’est intervenu sur la période. Si tel avait été le cas, je n’en aurais pas tenu compte car là encore il s’agit de perturbations prévues à l’avance.
Afin de ne pas trop allonger l’article, je passe sur les processus d’analyse pour me concentrer sur les résultats qui sont sans appel.
Une ligne de métro fonctionne environ 19h30 par jour (un peu plus les week-end), soit 136 heures et demie sur la période étudiée. Sur ces 136 heures, il y a eu 71 heures ou au moins une ligne était perturbée, soit 52% du temps. Le nombre cumulé d’heures de perturbation s’élève quant à lui à 96 heures.
Petite précision à apporter : l’API étant interrogée tous les quarts d’heure, les périodes de fonctionnement / dysfonctionnement sont donc étudiées par bloc de 15 minutes, ce qui apporte une légère approximation à cette étude.
Le graphique ci-dessous illustre les perturbations dans le métro tout au long de la période d’observation. On ne peut pas dire que le vert (quand tout va bien) domine franchement…
Si l’on s’intéresse à la répartition horaire du nombre d’incidents, on constate sans surprise qu’il faut éviter les heures de pointe, quand le réseau est le plus sollicité et le nombre de voyageurs le plus important.
En termes de fiabilité, la ligne 1 fait figure de référence avec seulement un quart d’heure de perturbation sur la période. A l’inverse, la 12 cumule à elle seule près de 20 heures, soit une journée de dysfonctionnement.
Les lignes 1 et 14, entièrement automatisées, sont en tête du peloton des lignes les plus fiables. Pourtant, la ligne 10, qui est la seule où le conducteur a pleinement la main sur la conduite, obtient une honorable troisième place. Pour information, les autres lignes sont semi automatisées. Le conducteur n’a en principe la main que sur les manœuvres d’ouverture / fermeture des portes et de départ du métro.
Mais qu’est ce qui provoque toutes ces perturbations ? En étudiant les mots qui apparaissent le plus on constate que les incidents ont deux types de cause :
- problèmes lié à une panne de matériel, le plus souvent une panne du réseau de signalisation ;
- problèmes liés aux voyageurs : bagages oubliés obligeant l’intervention des équipes de sécurité, personnes sur les voies ou encore malaises de passagers probablement liés au fait d’être entassé dans les rames en heure de pointe.
Conclusion
Ces 7 jours d’observation confirment la réalité des difficultés quotidiennement vécues par les millions d’usagers du métro parisien. A titre personnel je n’ai pas été surpris par les piètres résultats de la ligne 12, ayant été obligé de l’emprunter pendant plusieurs années.
Pour les visuels de la partie analyse de cet article, je me suis appuyé sur l’outil Plotly dash qui a l’avantage d’offrir de beaux rendus tout en étant relativement simple à prendre en main. Je l’ai découvert à l’occasion de ma prise de fonction chez la Javaness. Bien que je n’aie pas directement abordé l’utilisation de cet outil lors de ma formation de Data Analyst auprès de DataScientest, nous avons été largement encouragés à explorer et développer de nouvelles compétences. Comme je le dis régulièrement, un Data Analyst ne cesse jamais d’apprendre. Et c’est justement l’autonomie encouragée par DataScientest au cours de ma formation qui me permet aujourd’hui de le faire au quotidien.