Retour à la leçon·Leçon 4 sur 8·Pé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.
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.Quatre mesures, un seul mot
Mesure Numérateur Dénominateur Taux de rapportage Ensembles marqués complets Ensembles attendus Rapports effectifs Ensembles marqués complets — (un décompte) Rapports attendus — Unités affectées × périodes Taux de rapportage à temps Complétés avant l'échéance Ensembles 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.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 ».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.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.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)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.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.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 )Le taux de rapportage comme dénominateur de tout le reste
Mois Taux de rapportage Couverture parmi les déclarants Juillet 82 % … Août 29 % … Septembre 45 % … Octobre 95 % … 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.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.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%}")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)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.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, })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é.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é.