Introduction
Un atelier associatif prépare le matériel sept jours avant chaque séance. Prédire la fréquentation à partir des scans effectués après l'événement donnerait peut-être des résultats impressionnants, mais inutilisables à cette échéance. Vous établirez d'abord une référence simple, puis déciderez quelles lignes et colonnes une véritable prédiction anticipée peut utiliser.
Vous devez connaître les fonctions Python, la saisie élémentaire dans un terminal, la sélection et les jointures pandas, ainsi que les notions initiales de régression et de séparation entraînement/test. Python et les bibliothèques scientifiques sont prêts. Toutes les tables sont des données synthétiques originales à visée pédagogique ; ce petit échantillon démontre une démarche, sans garantir des prévisions en production. Les 55 minutes sont une estimation de l'auteur comprenant lecture et corrections ordinaires.
Mesurer une référence simple en personnes
Dans cette étape, vous prédirez deux séances ultérieures à partir d'une médiane antérieure et interpréterez l'erreur absolue moyenne.
Commencez dans WebIDE, puis ouvrez Terminal → New Terminal. L'éditeur et le terminal partagent les fichiers. cd change le répertoire de travail de ce terminal ; un nouveau terminal nécessite son propre cd.
cd /home/labex/project/workshop-attendance
Le lanceur préparé ./python utilise l'environnement Python du cours. ./ signifie « l'exécutable de ce répertoire ». Utilisez-le à la place du Python système pour les fichiers du cours. cat affiche un fichier texte sans le modifier.
cat warmup-early.csv
Ce petit exercice contient trois fréquentations réelles antérieures : 12, 18 et 24. Leur médiane, la valeur centrale après tri, est de 18 personnes. La référence prédit 18 pour chaque événement ultérieur sans utiliser de caractéristiques propres à l'événement.
cat warmup-later.csv
Les fréquentations ultérieures sont 20 pour L-7 et 27 pour L-2. Les erreurs absolues valent abs(20 - 18) = 2 et abs(27 - 18) = 9. L'erreur absolue moyenne (MAE) est leur moyenne : (2 + 9) / 2 = 5.5 personnes. « Une erreur moyenne de 5,5 personnes » est interprétable ; une « précision » sans unité masquerait la grandeur mesurée. Cet exercice est distinct de la saison complète utilisée ensuite.
Créez une fonction de référence réutilisable. La redirection shell > remplace baseline.py. Le here-document entre guillemets <<'PY' envoie dans ce fichier tout ce qui suit jusqu'à une ligne contenant uniquement PY, sans expansion par le shell. Collez le bloc entier, y compris son dernier PY. Vous pouvez aussi modifier le même fichier dans WebIDE et enregistrer avec File → Save.
Le lanceur transmet deux tables pandas à summarize. itertuples() parcourt les lignes avec des champs nommés ; le dictionnaire associe chaque identifiant de séance ultérieure à sa propre erreur. float convertit les valeurs numériques pandas en nombres Python ordinaires pour la sortie JSON.
cat > baseline.py <<'PY'
def summarize(early, later):
baseline = float(early.actual_attendance.median())
errors = {
row.session_id: float(abs(row.actual_attendance - baseline))
for row in later.itertuples()
}
return {
"median_attendance": baseline,
"absolute_errors": errors,
"mae": sum(errors.values()) / len(errors),
}
PY
Exécutez l'enveloppe préparée qui écrit les fichiers. Son argument baseline sélectionne cette phase ; elle enregistre le résultat de votre fonction dans output/baseline.json. JSON stocke des valeurs et objets nommés plutôt que des lignes CSV.
./python run.py baseline
Les valeurs affichées doivent inclure la médiane 18.0, les erreurs 2.0 et 9.0, et la MAE 5.5. Lisez le résultat enregistré avec le lecteur préparé, qui ne reconstruit jamais les résultats manquants.
./python show_results.py baseline
Vous disposez maintenant d'une référence dont l'erreur emploie les mêmes unités que le problème de planification. Un futur modèle doit être comparé sur les mêmes événements d'évaluation ; battre la valeur de cet exercice sur un autre échantillon ne serait pas une comparaison équitable.
Séparer le moment de l'entraînement de celui de la prédiction
Dans cette étape, vous associerez les résultats par identifiant de séance et réserverez les dates ultérieures à l'évaluation.
Continuez dans le même terminal WebIDE, à /home/labex/project/workshop-attendance. Lisez la frontière de saison et les trois tables principales.
cat season.json
cat history.csv
cat labels.csv
cat future.csv
Voici le dictionnaire des données :
| Champ | Signification et disponibilité | Utilisation |
|---|---|---|
session_id |
Identité stable de la séance ; ordre des fichiers arbitraire | Associer les lignes, jamais une caractéristique du modèle |
event_date |
Jour prévu de l'événement, format ISO YYYY-MM-DD |
Déterminer la séparation temporelle |
booked_7d |
Instantané des réservations enregistré exactement sept jours avant l'événement | Caractéristique numérique autorisée |
duration_minutes |
Durée déjà annoncée à l'échéance de sept jours | Caractéristique numérique autorisée |
final_bookings |
Total final des réservations lors de l'événement | Indisponible à l'échéance de prédiction |
scanned_entries |
Scans d'entrée collectés pendant l'événement | Indisponible à l'échéance de prédiction |
actual_attendance |
Résultat connu à la fin du jour de l'événement | Cible d'entraînement ou étiquette d'évaluation réservée |
Une cellule numérique CSV vide indique une information manquante, pas zéro réservation. Chaque caractéristique autorisée possède au moins une valeur observée d'entraînement. Les identifiants sont uniques dans chaque table ; labels.csv contient exactement un résultat par identifiant historique, volontairement dans un autre ordre. future.csv ne contient ni résultats ni colonnes postérieures à l'événement. Les clés invalides, les caractéristiques entièrement vides à l'entraînement et les mises à jour glissantes du modèle sortent du périmètre des entrées du cours.
Le modèle est entraîné une seule fois et figé le 1er avril 2026 à 00:00 UTC, as_of_date. Seuls les événements antérieurs peuvent fournir les étiquettes d'entraînement. Dans cette saison, la dernière séance d'entraînement est le 8 mars : ses étiquettes sont donc déjà disponibles. L'ensemble réservé commence le 12 avril, holdout_start ; sa première échéance de prédiction à sept jours est le 5 avril, après le gel de l'entraînement. Aucun événement historique fourni ne se situe dans l'intervalle.
Ce sont deux horloges différentes : le 1er avril fige le modèle ajusté ; chaque événement ultérieur fournit son propre instantané booked_7d à sa propre date de prédiction. L'instantané du 5 avril de l'événement du 12 avril est utilisé le 5 avril, sans prétendre le connaître le 1er avril. Cet exercice par fichiers rejoue les instantanés enregistrés. Les étiquettes réelles ultérieures ne sont révélées que pour mesurer rétrospectivement les performances. Les séances de mai dans future.csv restent des prévisions sans étiquettes.
Remplacez la séparation inachevée fondée sur les positions. Une jointure merge un-à-un associe les étiquettes par session_id ; elle ne suppose pas que la première ligne corresponde à la première ligne. pd.to_datetime analyse les dates du calendrier, pd.Timestamp les frontières configurées, puis des masques booléens sélectionnent les lignes correspondantes. Le tri par date puis par identifiant facilite la lecture ; l'orthographe de l'identifiant ne détermine jamais la période. .copy() crée des tables sélectionnées indépendantes.
cat > split.py <<'PY'
import pandas as pd
def split_events(history, labels, season):
events = history.merge(labels, on="session_id", validate="one_to_one")
dates = pd.to_datetime(events["event_date"])
train = events.loc[dates < pd.Timestamp(season["as_of_date"])].copy()
holdout = events.loc[dates >= pd.Timestamp(season["holdout_start"])].copy()
return (
train.sort_values(["event_date", "session_id"]),
holdout.sort_values(["event_date", "session_id"]),
)
PY
./python run.py split
L'ordre d'entraînement doit être W-91, W-04, W-77, W-12, W-63, W-02 ; les identifiants réservés sont W-88, W-09. Ces identifiants irréguliers montrent pourquoi ni l'ordre alphabétique ni les deux dernières lignes du fichier ne définissent la séparation.
./python show_results.py split
Vérifiez W-88 : il doit conserver la fréquentation réelle 46 issue de son étiquette correspondante, et non l'étiquette placée à la même position. Les fichiers enregistrés training.csv et holdout.csv comprennent encore les colonnes postérieures à l'événement pour les inspecter. L'étape suivante ne retiendra que les deux caractéristiques autorisées ; une colonne numérique n'est pas nécessairement légitime pour prédire.
Si vous fermez accidentellement le terminal, ouvrez Terminal → New Terminal et répétez le cd ci-dessus. Une erreur « No such file or directory » indique généralement un mauvais répertoire ou un nom mal saisi. Utilisez pwd pour afficher le chemin courant et ls pour lister ses fichiers, revenez dans cet espace de travail et relancez la bonne commande. Ne redémarrez pas le lab pour corriger une simple erreur de chemin.
Apprendre les moyennes d'imputation sur le seul entraînement
Dans cette étape, vous ajusterez un imputeur sur les séances antérieures puis le réutiliserez sur les instantanés ultérieurs sans apprendre de ceux-ci.
Continuez dans WebIDE, à /home/labex/project/workshop-attendance. Vous pouvez modifier baseline.py, split.py, prepare.py et vos fichiers output/. Conservez toutes les entrées CSV/JSON fournies, python, run.py, coursekit.py, show_results.py et chaque starter-*.py. Les copies initiales permettent de restaurer un module, mais vous pouvez également recoller sa version complète enseignée. Les fonctions principales doivent rester réutilisables lorsque dates, ordre des lignes et valeurs numériques changent.
L'imputation remplace une caractéristique manquante par une valeur apprise. SimpleImputer(strategy="mean") apprend la moyenne arithmétique de chaque colonne. Ici, les observations d'entraînement de booked_7d sont 10, 20, 40, 25 et 35 : leur moyenne est 26. Les six durées connues ont une moyenne de 80 minutes. Utiliser toutes les périodes permettrait aux séances ultérieures d'influencer ces choix d'entraînement, même sans leurs étiquettes de résultat. Ajustez après la séparation, pas avant.
FEATURES, fourni par coursekit, vaut exactement ['booked_7d', 'duration_minutes']. Les doubles crochets sélectionnent ces deux colonnes dans cet ordre. fit_transform apprend les moyennes et remplit la matrice d'entraînement ; transform réutilise ces moyennes pour les matrices réservée et future. statistics_ expose les moyennes apprises dans l'ordre des caractéristiques. Les tableaux renvoyés conservent l'ordre des lignes de chaque table d'entrée pour que l'enveloppe garde leurs identifiants.
cat > prepare.py <<'PY'
from sklearn.impute import SimpleImputer
from coursekit import FEATURES
def prepare_features(train, holdout, future):
imputer = SimpleImputer(strategy="mean")
training_values = imputer.fit_transform(train[FEATURES])
holdout_values = imputer.transform(holdout[FEATURES])
future_values = imputer.transform(future[FEATURES])
return training_values, holdout_values, future_values, imputer.statistics_
PY
./python run.py prepare
Les moyennes apprises doivent être booked_7d: 26.0 et duration_minutes: 80.0.
./python show_results.py prepare
Dans holdout-features.csv, W-88 utilise 26 réservations et ses 150 minutes observées ; W-09 conserve 90 réservations et utilise 80 minutes. Dans future-features.csv, F-101 utilise la même moyenne de réservations d'entraînement. Ni réservations finales, scans, dates, identifiants ou résultats n'entrent dans ces matrices numériques. Les cellules vides d'origine restent inchangées dans les fichiers sources.
Vous avez préparé une véritable frontière d'évaluation allant du passé vers la suite. Cela ne prouve pas que le futur se comporte comme le passé. Le prochain lab indépendant ajustera un petit modèle et comparera ses erreurs continues à une référence médiane d'entraînement sur le même ensemble réservé étiqueté. Les calculs équivalents et d'autres ordres de sortie sont acceptés si les associations par identifiant et le sens numérique restent identiques ; les comparaisons autorisent une tolérance absolue et relative de 1e-8.
Résumé
Vous avez créé une référence réutilisable fondée sur la médiane, mesuré la MAE en personnes, joint les résultats par identifiant et séparé les dates anciennes d'entraînement des dates ultérieures d'évaluation. Vous avez retenu uniquement les informations disponibles sept jours avant et ajusté les moyennes d'imputation sur les seules lignes d'entraînement. Les tables enregistrées conservent les identités d'origine et les données sources restent intactes pour la suite de l'analyse.



