Que montrent vraiment les trajectoires observées à YUL ?
Comment décrire le rythme et les liaisons de l'archive YUL sans les confondre avec le trafic officiel ?
À produire : Un tableau distinguant trajectoires et événements, une série mensuelle 2025 des départs observés et une interprétation écrite de deux limites précises.
Prérequis : Savoir importer un CSV et utiliser group_by(), summarise() et ggplot(). Distinguer une valeur manquante d'un zéro observé.
Préparation enseignante
Télécharger la trousse ZIP, l’extraire entièrement et ouvrir Donnees-bleues.Rproj. Installer les packages avec installer-packages.R avant la séance. Le script de l’activité utilise ensuite les trois CSV inclus, sans nouvelle acquisition.
Télécharger la trousse avec les données
6 000 Ko. Préparation : 23/09/2026 à 18:30 (heure du Québec).
Les fichiers de données sont inclus dans la trousse.
Conditions de la source · Provenance et empreinte du ZIP
Fichiers inclus
-
vols_yul.csv: 491 786 lignes, 11 colonnes. -
trafic_quotidien_yul.csv: 912 lignes, 4 colonnes. -
liaisons_yul.csv: 1 460 lignes, 6 colonnes.
Contexte
La fiche YUL présente une archive de trajectoires reconstituées à partir de signaux ADS-B. Une ligne de vols_yul.csv représente une trajectoire attribuée à CYUL. Une ligne de trafic_quotidien_yul.csv représente un jour du calendrier. Ces unités n’ont pas le même dénominateur.
Les données viennent des archives MrAirspace. Elles ne constituent pas les horaires publiés par Aéroports de Montréal et ne permettent pas de mesurer les retards. La trousse contient l’attribution et la licence ODbL.
Consignes
- Exécuter
activite-courte.Rdans le projet RStudio extrait de la trousse. - Expliquer pourquoi le total des départs et arrivées observés dépasse le nombre de trajectoires distinctes.
- Décrire la série mensuelle de 2025 en parlant d’observations dans l’archive, puis examiner les trois jours sans événement retenu.
- Lire le classement des destinations identifiées. Préciser ce qu’il exclut.
- Écrire une conclusion courte sur l’intérêt du jeu, avec deux limites qui changent l’interprétation.
Limites à faire nommer
La couverture des récepteurs ADS-B varie et l’aéroport peut être attribué de façon incertaine. Un zéro dans cette archive ne prouve pas l’absence de mouvements réels. Les heures sont celles de trajectoires détectées, et non des heures de porte certifiées.
Vérifier le travail
- Le tableau affiche 491 786 trajectoires et 494 352 événements, et explique l'écart de 2 566.
- Le graphique utilise la moyenne quotidienne de 2025, avec un axe et une légende précisant la couverture non exhaustive.
- La conclusion identifie deux limites, dont la couverture ADS-B ou l'attribution géographique à CYUL.
Objectifs et adaptations
Objectifs
- Expliquer pourquoi trajectoires distinctes et événements de départ ou d'arrivée ont des dénominateurs différents.
- Construire une moyenne quotidienne par mois sur une année entière.
- Formuler une conclusion descriptive sans prétendre mesurer le trafic officiel.
Adaptations
- Pour débuter, fournir le tableau de bilan et demander seulement son interprétation.
- Pour approfondir, comparer les trimestres en conservant la variable source_period et documenter les changements de méthode.
Statut documenté : Script exécuté et vérifié; activité non testée en classe.
Contribution pédagogique : Aurélien Nicosia. Usage en cours non documenté.
- Ajout
- Mise à jour
Code complet
Le code ci-dessous est le même que celui de la trousse. Il lit les fichiers locaux et affiche les résultats dans RStudio.
Afficher le script R
# Explorer les trajectoires observées à YUL, sans les confondre avec le trafic officiel.
# Ouvrir le projet RStudio de la trousse, puis exécuter ce script.
library(readr)
library(dplyr)
library(ggplot2)
vols <- read_csv("data/processed/vols-montreal-trudeau/vols_yul.csv",
show_col_types = FALSE)
trafic <- read_csv("data/processed/vols-montreal-trudeau/trafic_quotidien_yul.csv",
show_col_types = FALSE)
liaisons <- read_csv("data/processed/vols-montreal-trudeau/liaisons_yul.csv",
show_col_types = FALSE)
stopifnot(nrow(vols) == 491786L, nrow(trafic) == 912L,
nrow(liaisons) == 1460L)
# Une trajectoire locale à YUL contribue à la fois aux départs et aux arrivées.
bilan <- tibble(
trajectoires_distinctes = nrow(vols),
departs_observes = sum(trafic$n_departs_observes),
arrivees_observees = sum(trafic$n_arrivees_observees),
evenements_departs_arrivees = sum(trafic$n_evenements_observes),
trajectoires_locales_yul = sum(vols$sens == "local_yul")
)
stopifnot(bilan$evenements_departs_arrivees - bilan$trajectoires_distinctes ==
bilan$trajectoires_locales_yul)
print(bilan)
# Trois jours n'ont aucune observation retenue; ils ne prouvent pas une absence de vols.
print(trafic |>
filter(n_evenements_observes == 0) |>
select(date_locale, n_departs_observes, n_arrivees_observees))
# Décrire l'archive sur une année entière, sans lui attribuer une couverture constante.
mensuel_2025 <- trafic |>
filter(date_locale >= as.Date("2025-01-01"),
date_locale < as.Date("2026-01-01")) |>
mutate(mois = format(date_locale, "%Y-%m")) |>
group_by(mois) |>
summarise(jours = n(),
departs_par_jour = mean(n_departs_observes),
arrivees_par_jour = mean(n_arrivees_observees),
.groups = "drop")
print(mensuel_2025)
print(ggplot(mensuel_2025, aes(mois, departs_par_jour, group = 1)) +
geom_line(color = "#185b83", linewidth = 1) +
geom_point(color = "#185b83") +
labs(x = "Mois de 2025", y = "Départs observés par jour, en moyenne",
title = "Rythme mensuel dans l'archive ADS-B de YUL",
caption = "Archives MrAirspace : couverture variable, trafic non exhaustif") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)))
# Les liaisons ne sont disponibles que lorsque les deux aéroports sont identifiés.
principales_destinations <- liaisons |>
filter(origine_icao == "CYUL", destination_icao != "CYUL") |>
arrange(desc(n_observations), destination_icao) |>
slice_head(n = 10)
print(principales_destinations)
# À discuter : les durées manquantes et les codes d'aéroport ambiguës.
print(vols |>
summarise(durees_manquantes = sum(is.na(duree_observee_min)),
destinations_manquantes = sum(is.na(destination_icao)),
origines_manquantes = sum(is.na(origine_icao))))