cassionAnalyse de données

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

Le taux de rapportage est un dénominateur, pas une note de bas de page

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

    • Quatre mesures, un seul mot
    • Là où la réponse du système diffère de la vôtre
    • Le taux de rapportage comme dénominateur de tout le reste
    • Les deux façons de traiter une formation muette
    • Rapportez la paire
    • La suite
    Notes du présentateur
    Le système calcule quatre mesures de complétude et elles divergent. Celle que cite votre rapport décide si un taux de couverture est une estimation ou une borne inférieure, et août vaut 29 % dans les deux cas.
  2. Diapositive 2 / 19

    Quatre mesures, un seul mot

    MesureNumérateurDénominateur
    Taux de rapportageEnsembles marqués completsEnsembles attendus
    Rapports effectifsEnsembles marqués complets— (un décompte)
    Rapports attendus—Unités affectées × périodes
    Taux de rapportage à tempsComplétés avant l'échéanceEnsembles attendus
    Notes du présentateur
    Le cours Évaluation de la qualité des données a établi que la complétude du rapportage est un indicateur à part entière. Cette leçon porte sur ce que le système entend par là, car DHIS2 expose quatre mesures voisines sous des noms employés indifféremment.
  3. Diapositive 3 / 19

    Quatre mesures, un seul mot — En Python

    import pandas as pd
    
    vax = pd.read_csv("vaccination-coverage-2024.v1.csv", parse_dates=["period"])
    vax["reported"] = vax["report_submitted"] == True
    
    facility_months = vax.drop_duplicates(["facility_id", "period"])
    print(f"expected: {len(facility_months)}")
    print(f"actual:   {facility_months['reported'].sum()}")
    print(f"rate:     {facility_months['reported'].mean():.1%}")
    Notes du présentateur
    Le premier et le dernier ne diffèrent que par la promptitude, et un rapport citant « le taux de rapportage » sans préciser lequel laisse le lecteur incapable de dire si 82 % veut dire « transmis » ou « transmis à temps ».
  4. Diapositive 4 / 19

    Quatre mesures, un seul mot — En R

    library(dplyr)
    
    vax |>
      distinct(facility_id, period, .keep_all = TRUE) |>
      summarise(expected = n(), actual = sum(report_submitted),
                rate = mean(report_submitted))
    Notes du présentateur
    456 couples formation-mois attendus, 349 transmis, 76,5 %. Notez le dédoublonnage — la complétude est enregistrée par ensemble de données, unité et période, non par élément de données, si bien que compter les 2 736 lignes au niveau élément répondrait à une autre question et donnerait le même pourcentage par coïncidence.
  5. Diapositive 5 / 19

    Là où la réponse du système diffère de la vôtre

    • Les rapports attendus comptent l'affectation, non l'existence — Une formation fermée en mars reste au dénominateur le…
    • La complétude est un clic, non un calcul — Une formation peut saisir toutes ses valeurs sans jamais marquer le…
    Notes du présentateur
    Deux différences, et les deux ont pris des gens en défaut. Les rapports attendus comptent l'affectation, non l'existence. Une formation fermée en mars reste au dénominateur le reste de l'année tant que personne ne désaffecte l'ensemble de données ou ne ferme l'unité. Les taux de rapportage dérivent donc vers le bas à mesure que des formations ferment sans mise à jour des affectations, et cette dérive ressemble à une performance qui se dégrade. La complétude est un clic, non un calcul. Une formation peut saisir toutes ses valeurs sans jamais marquer le formulaire complet ; le système la compte comme non déclarante alors que les données sont là. L'inverse arrive aussi. Le taux de rapportage et la présence de données sont donc deux questions différentes.
  6. Diapositive 6 / 19

    Là où la réponse du système diffère de la vôtre — En Python

    has_data = (
        vax.groupby(["facility_id", "period"])["doses_administered"]
        .sum().gt(0).rename("has_data")
    )
    flags = facility_months.set_index(["facility_id", "period"])["reported"]
    
    crosstab = pd.crosstab(flags, has_data.reindex(flags.index))
    print(crosstab)
  7. Diapositive 7 / 19

    Là où la réponse du système diffère de la vôtre — En R

    vax |>
      summarise(reported = first(report_submitted),
                has_data = sum(doses_administered) > 0,
                .by = c(facility_id, period)) |>
      count(reported, has_data)
    Notes du présentateur
    Sur cette extraction les deux concordent exactement — tout mois rapporté a des doses et tout mois non rapporté n'en a aucune — ce qui est le cas net. Faites le tableau croisé quand même. Les cellules hors diagonale sont là où une instance réelle garde ses problèmes les plus intéressants, et une cellule « marqué complet, aucune donnée » est une formation qui transmet des formulaires vides pour atteindre une cible.
  8. Diapositive 8 / 19

    Le taux de rapportage comme dénominateur de tout le reste — En Python

    monthly = (
        vax[vax["antigen"] == "penta3"]
        .groupby(vax["period"].dt.strftime("%Y-%m"))
        .apply(lambda g: pd.Series({
            "reporting_rate": g["reported"].mean(),
            "coverage_reporting": (g.loc[g["reported"], "doses_administered"].sum()
                                   / g.loc[g["reported"], "target_population"].sum()),
        }))
    )
    print((monthly * 100).round(1))
    Notes du présentateur
    Le point opérationnel, et la raison pour laquelle cette leçon figure dans un cours DHIS2 et pas seulement dans celui d'évaluation.
  9. Diapositive 9 / 19

    Le taux de rapportage comme dénominateur de tout le reste — En R

    vax |>
      filter(antigen == "penta3") |>
      mutate(month = format(period, "%Y-%m")) |>
      summarise(
        reporting_rate = mean(report_submitted),
        coverage = sum(doses_administered[report_submitted]) /
                   sum(target_population[report_submitted]),
        .by = month
      )
  10. Diapositive 10 / 19

    Le taux de rapportage comme dénominateur de tout le reste

    MoisTaux de rapportageCouverture parmi les déclarants
    Juillet82 %…
    Août29 %…
    Septembre45 %…
    Octobre95 %…
  11. Diapositive 11 / 19

    Le taux de rapportage comme dénominateur de tout le reste

    • Trois règles en découlent, et elles sont le livrable de cette leçon
    • En dessous de 90 % de rapportage, un taux de couverture est une borne inférieure, non une estimation. Étiquetez-le…
    • Ne comparez pas deux périodes aux taux de rapportage sensiblement différents sans le dire. Août face à juillet…
    • Une courbe de tendance exige le taux de rapportage sur le même graphique. Tracée seule, une série de couverture…
    Notes du présentateur
    Deux colonnes, toujours adjacentes. Le taux de couverture d'août est calculé sur onze des trente-huit formations, et quoi qu'il dise, il le dit de ces onze-là. Trois règles en découlent, et elles sont le livrable de cette leçon.
  12. Diapositive 12 / 19

    Les deux façons de traiter une formation muette

    • L'exclure du numérateur et du dénominateur — Couverture parmi les formations ayant rapporté
    • Imputer ses doses — Remplir à partir des mois récents de la formation, en le disant
    Notes du présentateur
    Aucune n'est fausse. Elles répondent à des questions différentes et doivent être étiquetées. L'exclure du numérateur et du dénominateur. Couverture parmi les formations ayant rapporté. Honnête, et c'est ce que fait le code ci-dessus. Imputer ses doses. Remplir à partir des mois récents de la formation, en le disant. C'est ce que font les estimations nationales — WUENIC et exercices similaires imputent plutôt que de laisser des trous, car la question porte sur des enfants et non sur de la paperasse.
  13. Diapositive 13 / 19

    Les deux façons de traiter une formation muette — En Python

    by_facility = (
        vax[(vax["antigen"] == "penta3") & vax["reported"]]
        .groupby("facility_id")["doses_administered"].median()
    )
    missing = (vax["antigen"] == "penta3") & ~vax["reported"]
    imputed_total = (vax.loc[missing, "facility_id"].map(by_facility).sum()
                     + vax.loc[(vax["antigen"] == "penta3") & vax["reported"],
                               "doses_administered"].sum())
    
    annual_target = (vax[vax["antigen"] == "penta3"]
                     .groupby("facility_id")["target_population"].first().sum())
    print(f"imputed annual coverage: {imputed_total / annual_target:.1%}")
  14. Diapositive 14 / 19

    Les deux façons de traiter une formation muette — En R

    median_by_facility <- vax |>
      filter(antigen == "penta3", report_submitted) |>
      summarise(m = median(doses_administered), .by = facility_id)
  15. Diapositive 15 / 19

    Les deux façons de traiter une formation muette

    • N'imputez jamais en silence — Un chiffre imputé et un chiffre rapporté dans la même colonne sans marquage sont le…
    Notes du présentateur
    N'imputez jamais en silence. Un chiffre imputé et un chiffre rapporté dans la même colonne sans marquage sont le défaut que le cours de nettoyage a nommé — une estimation qu'on ne distingue plus d'une mesure.
  16. Diapositive 16 / 19

    Rapportez la paire — En Python

    summary = pd.DataFrame({
        "period": ["2024-08", "2024-09", "2024-10"],
        "facilities_reporting": [11, 17, 36],
        "facilities_expected": [38, 38, 38],
        "reporting_rate": ["29%", "45%", "95%"],
        "coverage_basis": ["among reporting facilities"] * 3,
    })
  17. Diapositive 17 / 19

    Rapportez la paire — En R

    tibble::tribble(
      ~period,   ~reporting, ~expected, ~basis,
      "2024-08",         11,        38, "among reporting facilities",
      "2024-09",         17,        38, "among reporting facilities",
      "2024-10",         36,        38, "among reporting facilities"
    )
    Notes du présentateur
    Cinq colonnes, et aucun taux de couverture ne circule sans elles. C'est tout l'argument, et c'est moins cher que la réunion où quelqu'un demande pourquoi août s'est effondré.
  18. Diapositive 18 / 19

    La suite

    • Tout ce qui précède a tourné sur un CSV exporté à la main.
    Notes du présentateur
    Tout ce qui précède a tourné sur un CSV exporté à la main. L'unité suivante le remplace — l'API Web, ce qu'il faut lui demander, et un script qui fait la même requête chaque mois en consignant ce qu'il a demandé.
  19. Diapositive 19 / 19

    La suite

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