Retour à la leçon·Leçon 7 sur 8·Ce que le suivi n'a pas vu
La tournée que personne n'a conduite
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
- Le dénominateur que personne n'a interrogé
- La couverture n'est pas répartie uniformément, et c'est tout le problème
- Encadrez la réponse
- L'absence est-elle aléatoire ?
- Ce qu'il ne faut pas faire
- Rapportez la couverture à côté de chaque taux
- La suite
Notes du présentateur
2 629 visites faites sur 2 904 dues. Nord-Ouest se lit comme le meilleur des trois districts à 76,4 % et sa réponse est incertaine à treize points près, contre deux et demi pour le district qui a presque tout visité.Le dénominateur que personne n'a interrogé — En Python
import pandas as pd points = pd.read_csv("water-point-monitoring-2024.v1.csv", parse_dates=["visit_date"]) due = points["water_point_id"].nunique() * 12 made = len(points) print(f"due {due:,}, made {made:,}, coverage {made / due:.1%}")Notes du présentateur
Tous les chiffres de fonctionnalité des deux dernières leçons divisaient par les visites faites. Personne n'a choisi ce dénominateur ; c'est ce qu'ungroupbyproduit à partir d'un fichier dont les lignes sont des visites. Le dénominateur que vous vouliez est celui des visites dues, et le registre sait ce que c'est : 242 points, douze tournées prévues.Le dénominateur que personne n'a interrogé — En R
library(dplyr) points |> summarise( due = n_distinct(water_point_id) * 12, made = n(), coverage = n() / (n_distinct(water_point_id) * 12) )Le dénominateur que personne n'a interrogé
- 2 629 sur 2 904 — une couverture de 90,5 % — Deux cent soixante-quinze tournées n'ont jamais été conduites, et le…
Notes du présentateur
2 629 sur 2 904 — une couverture de 90,5 %. Deux cent soixante-quinze tournées n'ont jamais été conduites, et le registre ne contient aucune ligne pour le dire. C'est le taux de rapportage du cours DHIS2 qui revient sous un autre format de fichier : une absence n'est pas une valeur, et rien dans les données ne vous rappellera qu'elle a eu lieu.La couverture n'est pas répartie uniformément, et c'est tout le problème — En Python
coverage = points.groupby("district").agg( points=("water_point_id", "nunique"), visits=("water_point_id", "size"), ) coverage["due"] = coverage["points"] * 12 coverage["coverage"] = coverage["visits"] / coverage["due"] print(coverage.round(3))La couverture n'est pas répartie uniformément, et c'est tout le problème — En R
points |> summarise(points = n_distinct(water_point_id), visits = n(), .by = district) |> mutate(due = points * 12, coverage = visits / due)La couverture n'est pas répartie uniformément, et c'est tout le problème
District Points Visites faites Dues Couverture Sud-Est 79 913 948 96,3 % Centre 79 882 948 93,0 % Nord-Ouest 84 834 1 008 82,7 % La couverture n'est pas répartie uniformément, et c'est tout le problème — En Python
monthly = points.pivot_table( index=points["visit_date"].dt.month, columns="district", values="water_point_id", aggfunc="size", ) print(monthly)Notes du présentateur
Les tournées de Nord-Ouest s'effondrent quand les routes se ferment.La couverture n'est pas répartie uniformément, et c'est tout le problème — En R
points |> count(district, month = lubridate::month(visit_date)) |> tidyr::pivot_wider(names_from = district, values_from = n)Notes du présentateur
D'environ 77 points par mois à entre 51 et 60 en juin, juillet, août et septembre. Centre et Sud-Est bougent à peine.Encadrez la réponse
- Borne haute : chaque visite manquée aurait trouvé un point en service. C'est le taux observé, qui suppose déjà que…
- Borne basse : chaque visite manquée aurait trouvé un point en panne.
Notes du présentateur
La réponse honnête à un dénominateur que vous ne pouvez pas observer entièrement n'est pas un facteur de correction. C'est une fourchette, calculée à partir des deux hypothèses qui encadrent la vérité.Encadrez la réponse — En Python
WORKING = {"functional", "partially-functional"} ok = points["functional_status"].isin(WORKING) bounds = points.assign(ok=ok).groupby("district").agg( ok=("ok", "sum"), made=("ok", "size"), points=("water_point_id", "nunique"), ) bounds["due"] = bounds["points"] * 12 bounds["observed"] = bounds["ok"] / bounds["made"] bounds["lower"] = bounds["ok"] / bounds["due"] bounds["band"] = bounds["observed"] - bounds["lower"] print((bounds[["observed", "lower", "band"]] * 100).round(1))Encadrez la réponse — En R
points |> mutate(ok = functional_status %in% c("functional", "partially-functional")) |> summarise(ok = sum(ok), made = n(), pts = n_distinct(water_point_id), .by = district) |> mutate(due = pts * 12, observed = ok / made, lower = ok / due)Encadrez la réponse
District Observé Borne basse Fourchette Nord-Ouest 76,4 % 63,2 % 13,2 Centre 75,7 % 70,5 % 5,3 Sud-Est 71,4 % 68,8 % 2,6 Encadrez la réponse
- Nord-Ouest est le meilleur district sur le chiffre observé et le seul dont le classement n'est pas sûr — Sa fourchette…
- Un nombre calculé sur 96 % de son dénominateur et un nombre calculé sur 83 % ne sont pas comparables, et rien dans le tableau ne le dira si vous ne l'y mettez pas
Notes du présentateur
Nord-Ouest est le meilleur district sur le chiffre observé et le seul dont le classement n'est pas sûr. Sa fourchette recouvre entièrement celles des deux autres. Sud-Est paraît le plus mauvais et c'est le seul dont on puisse être sûr, parce qu'il a visité presque tout. Un nombre calculé sur 96 % de son dénominateur et un nombre calculé sur 83 % ne sont pas comparables, et rien dans le tableau ne le dira si vous ne l'y mettez pas.L'absence est-elle aléatoire ? — En Python
observed = points.pivot_table( index="water_point_id", columns="round", values="functional_status", aggfunc="first", ) followed_by_gap = [] for point, row in observed.iterrows(): for r in range(1, 12): if pd.isna(row.get(r)): continue broken = row[r] not in WORKING followed_by_gap.append((pd.isna(row.get(r + 1)), broken)) check = pd.DataFrame(followed_by_gap, columns=["gap_next", "broken"]) print(check.groupby("gap_next")["broken"].agg(["mean", "size"]).round(3))Notes du présentateur
Les bornes sont larges parce qu'elles ne supposent rien. Les resserrer suppose de soutenir que les visites manquées ressemblent aux visites faites, et cet argument est testable.L'absence est-elle aléatoire ? — En R
# Same shape: was the point broken at the visit immediately before a missed round?L'absence est-elle aléatoire ?
- 26,7 % des visites suivies d'une tournée manquée ont trouvé un point en panne, contre 24,7 % des visites suivies d'une…
Notes du présentateur
26,7 % des visites suivies d'une tournée manquée ont trouvé un point en panne, contre 24,7 % des visites suivies d'une tournée faite. L'écart va dans le sens que l'on redoutait — un point que l'on sait en panne est un peu plus souvent sauté — et il est assez faible pour ne ni prouver ni écarter le biais. C'est un constat légitime et il doit être rapporté comme tel. Un test dont la réponse est ambiguë n'est pas un test raté ; il vous dit que les bornes ne peuvent pas honnêtement être resserrées, ce qui est ce qu'il fallait savoir.Ce qu'il ne faut pas faire
- Reporter la dernière observation — Remplir chaque tournée manquante par l'état précédent du point
- Imputer par la moyenne du district — Suppose que les points manqués ressemblent aux points visités du même district, ce…
- Retirer le district — Ôte du rapport le district le moins bien couvert, qui est presque toujours aussi le plus…
Notes du présentateur
Trois réparations qui paraissent toutes raisonnables. Reporter la dernière observation. Remplir chaque tournée manquante par l'état précédent du point. Cela donne 74,2 % au total, presque identique au taux observé, et c'est l'hypothèse qu'un point en panne le reste et qu'un point en service continue — c'est-à-dire exactement ce qui est en question. Cela fabrique de la précision sans ajouter d'information. Imputer par la moyenne du district. Suppose que les points manqués ressemblent aux points visités du même district, ce qui est l'hypothèse dont toute la leçon doute. Retirer le district. Ôte du rapport le district le moins bien couvert, qui est presque toujours aussi le plus difficile d'accès et le plus mal servi.Ce qu'il ne faut pas faire — En Python
print("Reported: 76.4% (observed), 63.2% to 76.4% (bounds), coverage 82.7%") print("Not reported: a single imputed number that hides which of these it is")Ce qu'il ne faut pas faire — En R
# The band and the coverage are the finding. Neither is a caveat.Rapportez la couverture à côté de chaque taux — Exemple
Water point functionality by district, 2024 District Functionality Coverage Range if unvisited were broken Sud-Est 71.4% 96.3% 68.8 - 71.4 Centre 75.7% 93.0% 70.5 - 75.7 Nord-Ouest 76.4% 82.7% 63.2 - 76.4 275 of 2,904 scheduled visits were not made, concentrated in Nord-Ouest during June to September when roads are impassable. Districts are not ranked here: Nord-Ouest's range overlaps both others.Notes du présentateur
Le taux, la couverture, la fourchette, et une phrase qui refuse de classer. Refuser de classer est un résultat, et c'est plus utile qu'un palmarès qui s'inverse dès que quelqu'un conduit les tournées manquantes.La suite
- Vous disposez maintenant de tous les nombres EAH que ce cours peut produire et d'un jeu de réserves attaché à chacun.
Notes du présentateur
Vous disposez maintenant de tous les nombres EAH que ce cours peut produire et d'un jeu de réserves attaché à chacun. La dernière leçon porte sur le rapport où ils vont — quels chiffres tiennent sur la même page, quels dénominateurs doivent être énoncés, et le tableau unique qui dit au lecteur ce qui peut être comparé avec quoi.