cassionAnalyse de données

Retour à la leçonLeçon 3 sur 8Périodes et complétude

Les périodes, et l'opérateur d'agrégation que personne ne règle

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.

Diapositives · PDFDiapositives · PowerPoint

  1. Diapositive 1 / 19

    Ce que couvre cette leçon

    • Types de période, et l'identifiant qui les porte
    • À quelle période appartient une valeur ?
    • Les trois chiffres annuels
    • Pourquoi ils diffèrent
    • L'opérateur d'agrégation
    • Échéances, expiration et verrouillage
    • La complétude est un enregistrement à part
    • La suite
    Notes du présentateur
    Un fichier, un indicateur, trois taux de couverture annuels — 6,5 %, 60,8 % et 77,5 % — tous issus de phrases qui sonnent défendables. La différence est la manière dont le dénominateur s'agrège dans le temps.
  2. Diapositive 2 / 19

    Types de période, et l'identifiant qui les porte — Exemple

    202408      monthly
    2024W32     weekly
    2024Q3      quarterly
    2024        yearly
    2024April   financial year starting April
    Notes du présentateur
    Toute valeur appartient à une période, et le type de période est une propriété de l'ensemble de données sur lequel elle a été collectée. Les identifiants de période de DHIS2 encodent le type dans la chaîne, ce qu'il vaut la peine d'adopter même hors DHIS2.
  3. Diapositive 3 / 19

    Types de période, et l'identifiant qui les porte — En Python

    import pandas as pd
    
    vax = pd.read_csv("vaccination-coverage-2024.v1.csv", parse_dates=["period"])
    vax["period_id"] = vax["period"].dt.strftime("%Y%m")
    print(sorted(vax["period_id"].unique())[:4])
    Notes du présentateur
    Ils se trient correctement, ils ne peuvent pas être ambigus entre conventions, et le type se lit sans schéma. Le cours sur les jointures plaidait pour des clés de période ISO ; c'est le même argument avec le vocabulaire du système.
  4. Diapositive 4 / 19

    Types de période, et l'identifiant qui les porte — En R

    library(dplyr)
    vax <- vax |> mutate(period_id = format(period, "%Y%m"))
  5. Diapositive 5 / 19

    À quelle période appartient une valeur ?

    • Juste — la période où l'activité a eu lieu. Une dose administrée le 28 août est d'août, quelle que soit la date…
    • Faux — la période où le formulaire a été transmis. Fréquent là où la saisie se fait par lots, et cela décale…
    • Faux — la période où la valeur a été saisie. Même défaillance, un cran plus loin.
    Notes du présentateur
    La question a une bonne réponse et deux mauvaises d'usage quotidien. DHIS2 stocke la valeur contre la période du formulaire de saisie ouvert, si bien que le système a raison si la personne a ouvert le bon formulaire. La défaillance est humaine et se manifeste par un motif caractéristique — un mois bas suivi d'un mois haut, le pic-et-creux que le cours d'évaluation vous a appris à chercher.
  6. Diapositive 6 / 19

    Les trois chiffres annuels — En Python

    penta3 = vax[vax["antigen"] == "penta3"]
    reported = penta3[penta3["report_submitted"] == True]
    
    doses = reported["doses_administered"].sum()
    
    summed_denominator = reported["target_population"].sum()
    annual_target = penta3.groupby("facility_id")["target_population"].first().sum()
    
    print(f"doses: {doses:,}")
    print(f"a) doses / summed monthly target : {doses / summed_denominator:.1%}")
    print(f"b) doses / annual target, all 38 : {doses / annual_target:.1%}")
    Notes du présentateur
    Voici la leçon. Prenez le penta3 sur l'année et demandez la couverture annuelle.
  7. Diapositive 7 / 19

    Les trois chiffres annuels — En R

    penta3 <- vax |> filter(antigen == "penta3")
    reported <- penta3 |> filter(report_submitted)
    
    doses <- sum(reported$doses_administered)
    summed <- sum(reported$target_population)
    annual <- penta3 |> summarise(t = first(target_population), .by = facility_id) |>
      summarise(sum(t)) |> pull()
    
    c(a = doses / summed, b = doses / annual)
  8. Diapositive 8 / 19

    Les trois chiffres annuels

    PhraseChiffre
    « Doses sur population cible, sommée sur l'année »6,5 %
    « Doses annuelles sur population cible annuelle »60,8 %
    « Doses annuelles sur cible annuelle, parmi les couples formation-mois ayant rapporté »77,5 %
    Notes du présentateur
    Trois nombres, un fichier, un indicateur, et chacun sort d'une phrase que quelqu'un prononcerait en réunion sans sourciller.
  9. Diapositive 9 / 19

    Pourquoi ils diffèrent

    • 6,5 % est un chiffre mensuel portant une étiquette annuelle — target_population est une cohorte annuelle — les…
    • 60,8 % compte les formations muettes comme n'ayant vacciné personne — Le dénominateur est la cohorte annuelle complète…
    • 77,5 % est le défendable — et il exige un ajustement explicite du dénominateur
    Notes du présentateur
    6,5 % est un chiffre mensuel portant une étiquette annuelle. target_population est une cohorte annuelle — les nourrissons survivants du bassin pour l'année — et l'extraction la répète chaque mois. La sommer sur douze mois produit un dénominateur douze fois trop grand. Le résultat est la couverture mensuelle moyenne, et la multiplier par douze ramène à 78 %. 60,8 % compte les formations muettes comme n'ayant vacciné personne. Le dénominateur est la cohorte annuelle complète de chaque formation, et le numérateur ne contient que les doses des couples formation-mois ayant rapporté. 107 des 456 couples penta3 manquent, et ce chiffre leur attribue zéro dose. 77,5 % est le défendable, et il exige un ajustement explicite du dénominateur.
  10. Diapositive 10 / 19

    Pourquoi ils diffèrent — En Python

    months_reported = reported.groupby("facility_id").size()
    targets = penta3.groupby("facility_id")["target_population"].first()
    prorated = (targets * months_reported.reindex(targets.index).fillna(0) / 12).sum()
    
    print(f"c) pro-rated denominator: {doses / prorated:.1%}")
  11. Diapositive 11 / 19

    Pourquoi ils diffèrent — En R

    months <- reported |> summarise(m = n(), .by = facility_id)
    targets <- penta3 |> summarise(t = first(target_population), .by = facility_id)
    
    prorated <- targets |>
      left_join(months, by = "facility_id") |>
      mutate(m = coalesce(m, 0)) |>
      summarise(sum(t * m / 12)) |> pull()
    
    doses / prorated
    Notes du présentateur
    Chaque formation contribue la part de sa cohorte annuelle correspondant aux mois qu'elle a effectivement rapportés. C'est une couverture parmi les couples formation-mois ayant rapporté, et le libellé doit le dire.
  12. Diapositive 12 / 19

    L'opérateur d'agrégation

    OpérateurSensConvient à
    SommeAdditionner entre périodesDécomptes d'événements — doses, admissions, consultations
    MoyenneMoyenne entre périodesNiveaux de stock, effectifs, tout ce qui est un état et non un événement
    Dernière valeurPrendre la plus récentePopulations, cibles, tailles de registre
    Notes du présentateur
    Sous ces trois chiffres se trouve un réglage de configuration que la plupart des analystes ne voient jamais — la façon dont un élément de données s'agrège entre périodes.
  13. Diapositive 13 / 19

    L'opérateur d'agrégation

    • Demandez l'opérateur d'agrégation avec les métadonnées — C'est un champ par élément de données, invisible dans…
    Notes du présentateur
    doses_administered se somme. target_population ne doit pas — c'est un état, et il se somme à douze fois lui-même. Dans une instance réelle, l'élément serait configuré en moyenne ou en dernière valeur, et demander la couverture annuelle fonctionnerait. Ici c'est une colonne répétée et la correction vous revient. Demandez l'opérateur d'agrégation avec les métadonnées. C'est un champ par élément de données, invisible dans l'export, et c'est la différence entre 6,5 % et 78 %. Le même réglage existe pour l'agrégation entre unités d'organisation, où « somme » est presque toujours juste et « moyenne » presque toujours fausse — les doses d'un district sont la somme de celles de ses formations, non leur moyenne.
  14. Diapositive 14 / 19

    Échéances, expiration et verrouillage

    • L'échéance est la date à laquelle l'ensemble de données est dû. Elle alimente le chiffre de promptitude que calcule…
    • Les jours d'expiration verrouillent le formulaire un nombre fixe de jours après la fin de la période. Ensuite, la…
    • Une exception de verrouillage déverrouille un ensemble, une unité, une période. Chacune est une décision, et un…
    Notes du présentateur
    Trois réglages qui déterminent si une valeur peut encore changer. Conséquence pour un analyste — une extraction d'une période récente est provisoire. Tirez août en septembre puis en novembre et les nombres différeront, légitimement, parce que la saisie tardive continue d'arriver. Ce n'est pas un problème de qualité et cela ne doit pas être rapporté comme tel — c'est la raison pour laquelle l'avant-dernière leçon consigne une date d'extraction à chaque tirage.
  15. Diapositive 15 / 19

    La complétude est un enregistrement à part

    • La complétude dans DHIS2 est un enregistrement, non un calcul — Quand un utilisateur clique « complet » sur un…
    Notes du présentateur
    Dernier point structurel, et il explique un nombre qui paraît sinon incohérent. La complétude dans DHIS2 est un enregistrement, non un calcul. Quand un utilisateur clique « complet » sur un formulaire de saisie, le système stocke un enregistrement de complétude pour cet ensemble, cette unité et cette période. Le taux de rapportage est construit à partir de ces enregistrements. Ce qui signifie qu'un ensemble peut être complet sans aucune valeur — quelqu'un a cliqué complet sur un formulaire vide — et plein de valeurs sans être complet — données saisies, personne n'a cliqué. Les deux arrivent constamment.
  16. Diapositive 16 / 19

    La complétude est un enregistrement à part — En Python

    grid = (vax["facility_id"].nunique() * vax["period"].nunique()
            * vax["antigen"].nunique())
    print(f"{grid} rows expected, {len(vax)} present, "
          f"{(vax['report_submitted'] == True).sum()} flagged reported")
  17. Diapositive 17 / 19

    La complétude est un enregistrement à part — En R

    c(expected = n_distinct(vax$facility_id) * n_distinct(vax$period) * n_distinct(vax$antigen),
      present = nrow(vax),
      reported = sum(vax$report_submitted))
    Notes du présentateur
    2 736 lignes présentes et 2 094 marquées comme rapportées. La ligne existe dans les deux cas, exactement la forme contre laquelle le cours de nettoyage mettait en garde — un rapport manquant qui arrive sous forme de zéro avec un indicateur à côté.
  18. Diapositive 18 / 19

    La suite

    • L'indicateur de rapportage est la matière première du chiffre de complétude, et la leçon suivante en fait un dénominateur.
    Notes du présentateur
    L'indicateur de rapportage est la matière première du chiffre de complétude, et la leçon suivante en fait un dénominateur. Le cours d'évaluation a déjà montré pourquoi cela compte ; celui-ci montre comment le système le calcule, et les deux façons dont sa réponse diffère de la vôtre.
  19. Diapositive 19 / 19

    La suite

    Lire la leçon complète, avec le code exécutable Retour à la leçon