Retour à la leçon·Leçon 7 sur 8·Produire et transmettre
Dates, âges et périodes de rapportage
Le même diaporama que les téléchargements, rendu sous forme de page. Lancez le diaporama pour le présenter en plein écran — les flèches ou un clic avancent d'une diapositive, Échap quitte.
Ce que couvre cette leçon
- Pourquoi cela mérite une leçon entière
- Analyser la date, une fois, explicitement
- L'âge en mois révolus
- Les périodes de rapportage
- Rééchantillonner une série temporelle
- Les durées
- Les fuseaux horaires, brièvement
- Ce qui vient ensuite
Notes du présentateur
L'âge en mois révolus calculé correctement plutôt qu'en divisant des jours, des périodes de rapportage qui survivent à un mois partiel, et l'arithmétique de frontière dont dépend un standard de croissance.Pourquoi cela mérite une leçon entière
- L'arithmétique des dates paraît être la partie facile et produit certaines des erreurs les plus coûteuses du secteur.
Notes du présentateur
L'arithmétique des dates paraît être la partie facile et produit certaines des erreurs les plus coûteuses du secteur. Un âge en mois décide du standard de croissance auquel un enfant est comparé. Une période de rapportage décide si une formation sanitaire compte comme ayant rapporté. Une frontière de mois décide si une distribution tombe dans les chiffres de ce trimestre ou du suivant. Aucun de ces cas n'échoue bruyamment.Analyser la date, une fois, explicitement — En Python
import pandas as pd muac = pd.read_csv(path) muac["screening_date"] = pd.to_datetime( muac["screening_date"], format="%Y-%m-%d", errors="raise" )Analyser la date, une fois, explicitement
- Énoncez le format. Un format inféré peut changer d'un fichier à l'autre selon la composition des valeurs — la même…
- Utilisez
errors="raise". L'alternative,errors="coerce", transforme toute date illisible en valeur manquante :…
Notes du présentateur
Deux habitudes à prendre :01/02/2024est soit le 1er février, soit le 2 janvier, et le fichier ne vous dira pas lequel. Si un export vous livre des dates ambiguës,dayfirst=Trueest une décision que vous documentez, non un réglage que vous acceptez.L'âge en mois révolus — En Python
# Faux assez souvent pour que cela compte. age_months = ((visit_date - date_of_birth).dt.days / 30.4375).astype(int)Notes du présentateur
L'approche évidente divise des jours par un mois moyen :L'âge en mois révolus — En Python
def age_in_months(dob: pd.Series, visit: pd.Series) -> pd.Series: months = (visit.dt.year - dob.dt.year) * 12 + (visit.dt.month - dob.dt.month) # Le quantieme n'est pas atteint : le dernier mois n'est pas revolu. return months - (visit.dt.day < dob.dt.day).astype(int)Notes du présentateur
Sur les deux mille premiers jours de vie, ce calcul diverge de la bonne réponse sur 54 d'entre eux — toujours d'un mois, toujours à une frontière. Un enfant de 60 jours est rapporté à 1 mois alors qu'il en a 2. Calculez directement les mois révolus :L'âge en mois révolus — En Python
dob = pd.to_datetime(["2022-03-15", "2022-03-16", "2022-02-28"]) visit = pd.to_datetime(["2024-03-15", "2024-03-15", "2024-03-01"]) age_in_months(pd.Series(dob), pd.Series(visit)).tolist() # [24, 23, 24]L'âge en mois révolus
- Pourquoi un mois compte ici
- Les standards de croissance de l'OMS changent de mesure exactement à 24 mois — En dessous de 24 mois, l'enfant est…
- Les tranches d'âge sont l'autre endroit —
0-5,6-23,24-59mois sont les tranches nutritionnelles standard, et un…
Notes du présentateur
Le deuxième enfant est à un jour de ses deux ans : il a 23 mois, non 24. Ce seul jour est toute la raison d'être de cette fonction. Les standards de croissance de l'OMS changent de mesure exactement à 24 mois. En dessous de 24 mois, l'enfant est mesuré couché et comparé à la courbe poids-pour-longueur ; à partir de 24 mois, debout, contre le poids-pour-taille. Les deux mesures diffèrent d'environ 0,7 cm et les deux courbes sont des tables différentes. Un enfant poussé de 23 à 24 mois par une règle d'arrondi est comparé au mauvais standard, et son score Z se déplace. Faites cela à quelques centaines d'enfants près de la frontière et l'estimation de prévalence se déplace avec eux — c'est pourquoi le projet Analyse d'enquête SMART rapporte l'attraction des âges vers les années entières comme un constat de plausibilité et non comme une curiosité. Les tranches d'âge sont l'autre endroit.0-5,6-23,24-59mois sont les tranches nutritionnelles standard, et un enfant à exactement 24 mois appartient à la troisième :L'âge en mois révolus — En Python
BANDS = [0, 6, 24, 60] LABELS = ["0-5m", "6-23m", "24-59m"] muac["age_band"] = pd.cut( muac["age_months"], bins=BANDS, labels=LABELS, right=False, include_lowest=True )L'âge en mois révolus — En Python
check = muac.loc[muac["age_months"].isin([5, 6, 23, 24, 59, 60]), ["age_months", "age_band"]].drop_duplicates().sort_values("age_months") print(check)Notes du présentateur
right=Falserend chaque intervalle[bas, haut)— fermé à gauche, ouvert à droite — de sorte que 24 mois tombe dans24-59met non dans6-23m. Le comportement par défaut est l'inverse, et il est faux pour toutes les tranches d'âge employées dans ce secteur. Vérifiez les frontières plutôt que de leur faire confiance :Les périodes de rapportage — En Python
muac["month"] = muac["screening_date"].dt.to_period("M") by_month = muac.groupby("month").size()Notes du présentateur
Une période est un mois, un trimestre ou une année pour lequel on rapporte, et ce n'est pas la même chose qu'une date.Les périodes de rapportage — Exemple
2024-01 207 2024-02 391 ... 2024-11 375 2024-12 156Les périodes de rapportage — En Python
current = pd.Period("2024-06", freq="M") print(current - 1) # 2024-05 print(current.start_time, current.end_time)Notes du présentateur
Les périodes se trient correctement, s'affichent lisiblement et — contrairement à une chaîne comme"2024-01"— acceptent l'arithmétique :Les périodes de rapportage
- Les périodes partielles sont le piège
Notes du présentateur
Les chaînes se trient aussi correctement si vous employez l'ordre ISO, bonne raison d'utiliser%Y-%met jamais%m/%Y. Mais une chaîne ne sait pas répondre à « le mois précédent », et cette question surgit dans tout calcul de tendance. Ce registre court du 15 janvier au 13 décembre. Janvier porte 207 dépistages et décembre 156, contre une moyenne mensuelle proche de 375. Aucun de ces deux mois n'est une baisse ; les deux sont partiels.Les périodes de rapportage — En Python
first, last = muac["screening_date"].min(), muac["screening_date"].max() print(first.date(), last.date()) muac["partial_period"] = muac["month"].isin( [first.to_period("M"), last.to_period("M")] )Les périodes de rapportage
- Étiquetez-les plutôt que de les supprimer — Un lecteur qui voit décembre s'effondrer sur un graphique conclut que le…
- Aligner deux sources sur des périodes
Notes du présentateur
Étiquetez-les plutôt que de les supprimer. Un lecteur qui voit décembre s'effondrer sur un graphique conclut que le programme s'est écroulé ; un lecteur qui ne voit aucun décembre se demande où sont passées les données. Nommer le mois partiel est la seule option qui répond aux deux. La même logique vaut pour une période inachevée. Un cumul en cours de mois comparé à des mois révolus est la façon la plus courante dont un tableau de bord affiche une baisse fictive tous les mois, et cela arrive parce que les deux s'appellent « le total mensuel ». L'extraction de vaccination enregistre une date de début de période plutôt qu'une date de prestation :Les périodes de rapportage — En Python
epi = pd.read_csv(path, parse_dates=["period"]) epi["month"] = epi["period"].dt.to_period("M") print(epi["month"].nunique()) # 12Notes du présentateur
Convertir les deux sources enPeriodavant la jointure est ce qui les fait coïncider. Joindre une date à un début de période ne produit silencieusement aucune correspondance pour chaque mois où une source a utilisé le dernier jour et l'autre le premier.Rééchantillonner une série temporelle — En Python
daily = muac.set_index("screening_date") weekly = daily.resample("W")["child_id"].size() monthly = daily.resample("MS")["child_id"].size() # MS = debut de moisNotes du présentateur
Quand l'index est un datetime,resampleagrège par période sans colonne de regroupement manuelle :resamplecomble les trous : une semaine sans dépistage apparaît à zéro plutôt que d'être absente. C'est juste pour une série temporelle et faux pour un dénominateur — une école fermée quinze jours n'a pas de jours de présence, et non une présence nulle ; le projet Assiduité scolaire montre ce que coûte le remplissage.Les durées — En Python
referrals["days_to_service"] = ( referrals["service_date"] - referrals["referral_date"] ).dt.daysNotes du présentateur
Soustraire deux datetimes donne unTimedelta:Les durées — En Python
hours = (referrals["service_date"] - referrals["referral_date"]) / pd.Timedelta(hours=1) referrals["same_day"] = hours < 24Notes du présentateur
.dt.daystronque vers zéro : un écart de 23 heures vaut 0 jour. Si le même jour compte — et pour un référencement en protection, c'est le cas — dites-le explicitement plutôt que de laisser la troncature décider :Les durées — En Python
impossible = referrals["days_to_service"] < 0 print(f"service saisi avant le referencement : {impossible.sum()}")Notes du présentateur
Une durée négative est un constat de qualité des données, non une valeur dont on prend la valeur absolue :Les fuseaux horaires, brièvement — En Python
submissions["submitted_at"] = pd.to_datetime( submissions["submitted_at"], utc=True ).dt.tz_convert("America/Port-au-Prince") submissions["submission_date"] = submissions["submitted_at"].dt.dateNotes du présentateur
Les données de programme sont généralement des dates locales naïves et doivent le rester. Attacher un fuseau à une date de dépistage invite une conversion qui fera franchir minuit à un enregistrement et le fera basculer dans le mauvais mois de rapportage. Là où des horodatages portent réellement un fuseau — heures de soumission des formulaires CommCare ou Kobo côté serveur — convertissez une fois, à la frontière, et stockez la date locale : L'horodatage de soumission et la date de la visite qu'il enregistre sont deux choses différentes, et rapporter la première quand on veut dire la seconde décale toute soumission du soir vers le lendemain.Ce qui vient ensuite
- Chaque colonne dit désormais ce qu'elle signifie, y compris celles faites de dates.
Notes du présentateur
Chaque colonne dit désormais ce qu'elle signifie, y compris celles faites de dates. La dernière leçon transforme l'analyse en un script qu'un autre chargé pourra exécuter au trimestre prochain sur un autre export, sans rien modifier d'autre que ses arguments.