Leçon 2 sur 8
Unité · Ce que qualité veut dire ici
Les deux indicateurs que personne ne calcule
Complétude et promptitude du rapportage, chacune avec son dénominateur. Onze formations sanitaires sur trente-huit ont rapporté en août, et tout taux de couverture de ce mois est une affirmation sur ces onze-là.
Deux indicateurs, et aucun n’est dans le rapport
Ouvrez presque n’importe quel rapport sanitaire de routine de ce secteur et vous y trouverez la couverture, la charge de cas, les taux de guérison et les ruptures de stock. Vous y trouverez très rarement les deux chiffres qui disent quelle part du district ces figures décrivent.
Ils sont bon marché. Les deux sortent de l’extraction que vous avez déjà — enfin, l’un des deux — et les deux changent la manière dont il faut lire tous les autres nombres du rapport.
La complétude du rapportage
Le taux de rapportage est la part des rapports attendus qui ont effectivement été transmis. Le mot qui travaille est attendus.
import pandas as pd
vax = pd.read_csv("vaccination-coverage-2024.v1.csv", parse_dates=["period"])
vax["reported"] = vax["report_submitted"] == True
print(f"overall reporting rate: {vax['reported'].mean():.1%}")
by_month = vax.groupby(vax["period"].dt.strftime("%Y-%m"))["reported"].mean()
print((by_month * 100).round(0))
library(dplyr)
library(readr)
vax <- read_csv("vaccination-coverage-2024.v1.csv")
mean(vax$report_submitted)
vax |>
mutate(month = format(period, "%Y-%m")) |>
summarise(reporting_rate = mean(report_submitted), .by = month) |>
arrange(month)
| Mois | Taux de rapportage |
|---|---|
| Janvier | 92 % |
| Février | 82 % |
| Mars | 74 % |
| Avril à juillet | 82 à 87 % |
| Août | 29 % |
| Septembre | 45 % |
| Octobre | 95 % |
| Novembre et décembre | 76 à 87 % |
Août et septembre ne sont pas une oscillation. Onze formations sanitaires sur trente-huit ont rapporté en août et dix-sept en septembre. Tout taux de couverture d’août est une affirmation sur onze formations, et le publier à côté de celui de juillet sans le dire revient à comparer deux districts différents.
Remarquez aussi que l’effondrement et la reprise sont simultanés dans tout le district. C’est la signature d’un événement de système — un stock de formulaires papier, une grève, un serveur, un superviseur parti — et non de formations qui défaillent individuellement. Une évaluation qui soulève 27 constats séparés pour août a mal lu le motif.
Décomposez toujours de trois façons
Un nombre unique masque tout ce qui mérite d’être su. Décomposez le taux de rapportage par période, par unité de rapportage et par type d’unité.
by_facility = vax.groupby("facility_id")["reported"].mean().sort_values()
print(by_facility.head(6))
print(f"{(by_facility == 1).sum()} facilities reported every month")
by_type = vax.groupby("facility_type")["reported"].mean()
print((by_type * 100).round(1))
vax |> summarise(rate = mean(report_submitted), .by = facility_id) |> arrange(rate) |> head(6)
vax |> summarise(rate = mean(report_submitted), .by = facility_type)
| Type de formation | Taux de rapportage |
|---|---|
| Centre de santé | 82,8 % |
| Hôpital de district | 75,0 % |
| Poste de santé | 71,7 % |
Les six pires formations sont toutes à 58 % — sept mois sur douze — et seules deux sur trente-huit ont rapporté tous les mois. Le gradient par type est le constat actionnable : ce sont les postes de santé qui rapportent le moins bien, ce qui désigne la distance de supervision, les effectifs ou le transport plutôt qu’une formation en particulier.
Le piège du dénominateur
L’erreur unique qui rend un taux de rapportage inutile.
# WRONG: the share of reports that were submitted, among reports that were submitted
wrong = vax[vax["reported"]]["reported"].mean() # always 1.0
# WRONG
vax |> filter(report_submitted) |> summarise(rate = mean(report_submitted))
Évident une fois écrit. Cela ne l’est pas quand le filtre est six lignes plus haut dans une chaîne, et c’est exactement ce qui arrive lorsqu’on lit une extraction DHIS2 ne contenant que les rapports transmis. Si l’extraction ne comporte aucune ligne pour les unités non déclarantes, le taux de rapportage ne peut pas y être calculé du tout — il vous faut la liste des unités attendues, prise ailleurs.
EXPECTED_FACILITIES = pd.read_csv("facility-master-list.csv")["facility_id"]
expected = len(EXPECTED_FACILITIES) * vax["period"].nunique()
submitted = vax.loc[vax["reported"], ["facility_id", "period"]].drop_duplicates().shape[0]
print(f"{submitted} of {expected} expected facility-months")
expected <- nrow(facility_master) * n_distinct(vax$period)
submitted <- vax |> filter(report_submitted) |> distinct(facility_id, period) |> nrow()
La liste de référence fait autorité, exactement comme la base administrative de population dans le cours précédent. Une formation fermée et une formation qui a cessé de rapporter sont identiques dans l’extraction et constituent des constats totalement différents, et seule la liste de référence les distingue.
La promptitude exige un champ que vous n’avez peut-être pas
La promptitude est la part des rapports transmis avant l’échéance, et le retard médian des autres.
submissions["days_late"] = (
submissions["submitted_on"] - submissions["deadline"]
).dt.days
print(f"on time: {(submissions['days_late'] <= 0).mean():.1%}")
print(f"median days late, of those late: "
f"{submissions.loc[submissions['days_late'] > 0, 'days_late'].median():.0f}")
submissions <- submissions |>
mutate(days_late = as.integer(submitted_on - deadline))
c(on_time = mean(submissions$days_late <= 0),
median_late = median(submissions$days_late[submissions$days_late > 0]))
Cette extraction ne permet pas ce calcul, et le dire est en soi un constat
d’évaluation. Il n’y a pas d’horodatage de transmission dans le fichier — seulement
report_submitted, un indicateur sans date. DHIS2 enregistre un lastUpdated par
ensemble de valeurs et une date de complétude par enregistrement, si bien que le
champ existe dans le système et n’a pas été repris dans l’export.
Consignez-le tel quel.
Constat. La promptitude ne peut pas être évaluée. L’extraction mensuelle porte un indicateur de transmission mais aucune date de transmission, alors que DHIS2 en enregistre une. Action corrective. Ajouter la date de complétude à l’extraction standard. Responsable. Point focal SNIS. Échéance. Prochaine extraction trimestrielle.
Une dimension que vous ne pouvez pas mesurer est un constat sur le système de rapportage, non une lacune de votre évaluation. Rapportez-la dans le même tableau que le reste.
Lisez tous les autres chiffres à travers ces deux-là
L’intérêt de les calculer en premier tient à ce qu’ils vous autorisent à dire ensuite.
- La couverture, à 76,5 % de rapportage. Un total de district est une borne inférieure, pas une estimation. Écrivez « parmi les formations ayant rapporté » dans le libellé, à chaque fois.
- Une tendance mensuelle. La baisse d’août est une baisse de rapportage jusqu’à preuve du contraire. Tracez le taux de rapportage sur le même graphique que l’indicateur, et la question se répond d’elle-même.
- Un classement de formations. Des formations ayant rapporté sept mois sur douze ne peuvent pas être classées face à des formations en ayant rapporté douze. Soit vous limitez le classement à un ensemble commun de mois, soit vous classez sur une moyenne mensuelle en affichant le décompte.
monthly = (
vax[vax["reported"]]
.groupby(vax["period"].dt.strftime("%Y-%m"))
.apply(lambda g: g["doses_administered"].sum() / g["target_population"].sum())
.rename("coverage")
.to_frame()
)
monthly["reporting_rate"] = by_month
print(monthly.round(3))
vax |>
mutate(month = format(period, "%Y-%m")) |>
summarise(
coverage = sum(doses_administered[report_submitted]) /
sum(target_population[report_submitted]),
reporting_rate = mean(report_submitted),
.by = month
)
Deux colonnes, toujours adjacentes. Un taux de couverture sans son taux de rapportage est un nombre sans étiquette, et l’étiquette est ce qui l’empêche d’être mal lu.
La suite
Complétude et promptitude disent si un rapport est arrivé. La leçon suivante dit s’il était juste — le recomptage face au registre source, le facteur de vérification qu’il produit, et la bande de tolérance qui en fait une décision.