Retour à la leçon·Leçon 6 sur 8·Les verbes
Là où naissent la plupart des erreurs d'indicateurs
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
- Un indicateur, ce sont deux nombres
n()et les deux façons de compter- Le regroupement survit, et c'est l'erreur la plus fréquente
- Une clé manquante devient son propre groupe
- Niveaux de facteur inutilisés :
count()écarte,table()conserve mutate()groupé : une statistique de groupe sur chaque lignecount()quand c'est tout ce que vous voulez- Deux clés, et le tableau qu'attend un rapport
- Écrire le résultat
- Les trois renversements, en un seul endroit
- Ce qui vient ensuite
Notes du présentateur
group_by() et summarise() — le regroupement qui survit à l'appel, la clé manquante qui devient son propre groupe, et les trois comportements par défaut exactement inverses de ceux de pandas.Un indicateur, ce sont deux nombres — En R
library(dplyr) by_commune <- muac |> mutate( assessed = !is.na(muac_mm) | !is.na(oedema), gam = assessed & (muac_mm < 125 | oedema == "true") ) |> group_by(commune) |> summarise( screened = n(), assessed = sum(assessed, na.rm = TRUE), gam_cases = sum(gam, na.rm = TRUE), .groups = "drop" ) |> mutate(gam_rate = round(gam_cases / assessed, 3))Notes du présentateur
Presque tout chiffre rapporté dans ce secteur est un numérateur sur un dénominateur, et presque toute dispute sur un chiffre est une dispute sur le dénominateur. La conséquence pratique : calculez les deux dans le même appel. Trois colonnes, et chacune porte quelque chose.screenedest le nombre d'enfants venus ;assessedle nombre ayant produit une mesure exploitable, et c'est le dénominateur ;gam_casesest le numérateur. Deux calculs séparés divergent — l'un reçoit un filtre que l'autre n'a pas — et le rapport devient un chiffre que personne ne peut reconstituer.n()et les deux façons de compter — En Rsummarise(muac, rows = n(), measured = sum(!is.na(muac_mm)))n()et les deux façons de compter — En Rsum(c(TRUE, NA)) #> [1] NA sum(c(TRUE, NA), na.rm = TRUE) #> [1] 1Notes du présentateur
n()compte les lignes du groupe, y compris celles à valeur manquante. Sommer un booléen compte lesTRUE. Cette distinction fait la différence entre les deux dénominateurs ci-dessus, et mérite d'être énoncée à voix haute chaque fois que vous employez l'un des deux.sum()sur un booléen contenantNArenvoieNA— R, encore une fois, bruyant : Recourez àna.rm = TRUEdélibérément, en sachant qu'il retire la ligne du décompte au lieu de la compter commeFALSE. Ce sont deux affirmations différentes.Le regroupement survit, et c'est l'erreur la plus fréquente — En R
out <- muac |> mutate(month = format(screening_date, "%Y-%m")) |> group_by(commune, month) |> summarise(n = n())Notes du présentateur
C'est le point à intérioriser.summarise()retire la dernière variable de regroupement et laisse les autres :Le regroupement survit, et c'est l'erreur la plus fréquente — Exemple
`summarise()` has regrouped the output. ℹ Summaries were computed grouped by commune and month. ℹ Output is grouped by commune. ℹ Use `summarise(.groups = "drop_last")` to silence this message.Le regroupement survit, et c'est l'erreur la plus fréquente — En R
class(out)[1] #> [1] "grouped_df" dplyr::group_vars(out) #> [1] "commune"Le regroupement survit, et c'est l'erreur la plus fréquente — En R
out |> mutate(share = n / sum(n)) # part dans la commune, non dans le district out |> arrange(desc(n)) # trie a l'interieur de chaque commune out |> slice_max(n, n = 5) # top 5 par commune, non au totalNotes du présentateur
Le résultat est encore groupé par commune. Chaque verbe qui suit opère silencieusement par commune :Le regroupement survit, et c'est l'erreur la plus fréquente
- Dites ce que vous voulez, à chaque fois
Notes du présentateur
Chacune de ces lignes produit un chiffre plausible qui répond à une autre question que la vôtre. Rien ne lève d'erreur. Dites ce que vous voulez, à chaque fois :Le regroupement survit, et c'est l'erreur la plus fréquente — En R
summarise(..., .groups = "drop") # resultat degroupe — la reponse habituelle summarise(..., .groups = "drop_last") # garder tout sauf la derniere (le defaut) summarise(..., .groups = "keep") # tout garderLe regroupement survit, et c'est l'erreur la plus fréquente — En R
muac |> summarise(n = n(), .by = c(commune, month))Notes du présentateur
Ou évitez complètement cet état avec le regroupement par opération, apparu dans dplyr 1.1 :.bygroupe pour ce seul appel et renvoie un résultat dégroupé. Préférez-le dans du code neuf : sans état résiduel, il n'y a pas d'erreur de cette forme.Une clé manquante devient son propre groupe — En R
d <- tibble::tibble(g = c("a", NA, "a"), v = c(1, 2, 3)) d |> group_by(g) |> summarise(s = sum(v), .groups = "drop")Notes du présentateur
Ici, R et pandas prennent des paris opposés.Une clé manquante devient son propre groupe — Exemple
# A tibble: 2 × 2 g s <chr> <dbl> 1 a 4 2 <NA> 2Une clé manquante devient son propre groupe — En R
d |> filter(!is.na(g)) |> group_by(g) |> summarise(s = sum(v), .groups = "drop")Notes du présentateur
Le groupeNAest conservé. pandas l'écarte par défaut : la même opération dans les deux langages vous donne donc un ensemble de lignes différent et un total différent. Le comportement de R est le plus sûr, et dans ce secteur la clé manquante est généralement la plus intéressante : une formation sanitaire sans district saisi, un ménage sans code de site, un enfant sans commune. Mais cela signifie qu'un tableau peut arriver dans un rapport avec une ligne<NA>que personne n'avait prévu de publier.Une clé manquante devient son propre groupe — En R
stopifnot(!any(is.na(muac$commune)))Notes du présentateur
L'exclure est légitime. L'exclure sans le remarquer, c'est ainsi que les parties cessent de faire le tout. Préférez une assertion là où la clé devrait être complète :Niveaux de facteur inutilisés :
count()écarte,table()conserve — En Rd <- tibble::tibble(k = factor(c("a", "b", "a"), levels = c("a", "b", "c"))) nrow(count(d, k)) #> 2 — le niveau vide a disparu nrow(count(d, k, .drop = FALSE)) #> 3 — conserve length(table(d$k)) #> 3 — conserveNotes du présentateur
Le second renversement, et R n'est pas cohérent avec lui-même ici — raison pour laquelle la leçon sur les facteurs l'aborde et celle-ci le répète.Niveaux de facteur inutilisés :
count()écarte,table()conserve- Passez
.dropexplicitement — dans tout ce qui produit un tableau rapporté
Notes du présentateur
Les deux sont justes pour des questions différentes, et c'est la question même que le cours Python soulève à propos d'observed=. Rapporter sur les formations ayant transmis des données veut le niveau vide en moins ; rapporter la couverture face à une liste de formations qui auraient dû transmettre le veut présent, car une formation à zéro ligne est justement le constat. Passez.dropexplicitement dans tout ce qui produit un tableau rapporté.- Passez
mutate()groupé : une statistique de groupe sur chaque ligne — En Rmuac |> group_by(commune) |> mutate( commune_mean = mean(muac_mm, na.rm = TRUE), vs_commune = muac_mm - commune_mean ) |> ungroup()Notes du présentateur
summarise()réduit ;mutate()sur un tableau groupé renvoie une valeur par ligne d'origine. C'est ainsi qu'on compare une ligne à son propre groupe sans jointure :mutate()groupé : une statistique de groupe sur chaque ligne- Noter le
ungroup()— Un tableau groupé qui s'échappe dans la suite d'un script est la même erreur que ci-dessus,…
Notes du présentateur
C'est le contrôle qu'emploie le projet Analyse d'enquête SMART pour repérer une équipe mesurant un demi-kilo trop léger. Noter leungroup(). Un tableau groupé qui s'échappe dans la suite d'un script est la même erreur que ci-dessus, arrivant par une autre porte.- Noter le
count()quand c'est tout ce que vous voulez — En Rmuac |> count(commune, outcome, sort = TRUE) muac |> count(commune, wt = muac_mm) # sommer une colonne plutot que compterNotes du présentateur
count()groupe, compte et dégroupe en un appel : il ne peut donc pas laisser d'état derrière lui. Là où un décompte suffit, c'est le meilleur verbe.Deux clés, et le tableau qu'attend un rapport — En R
by_commune_month <- muac |> mutate(month = format(screening_date, "%Y-%m")) |> summarise(cases = sum(gam, na.rm = TRUE), .by = c(commune, month)) wide <- by_commune_month |> tidyr::pivot_wider(names_from = month, values_from = cases, values_fill = 0)Notes du présentateur
values_fill = 0est sans risque ici, car une commune-mois sans cas en avait réellement zéro. Ce serait faux pour un taux, où l'absence signifie « non calculé » et non « zéro pour cent » — distinction à vérifier chaque fois que vous y recourez.Écrire le résultat — En R
readr::write_csv(by_commune, here::here("outputs", "tables", "gam_by_commune.csv"))Écrire le résultat — En R
definitions <- tibble::tibble( indicateur = "MAG", numerateur = "PB < 125 mm ou oedemes bilateraux prenant le godet", denominateur = "enfants avec une mesure de PB ou une evaluation d'oedemes saisie" ) readr::write_csv(definitions, here::here("outputs", "tables", "definitions.csv"))Notes du présentateur
Pour un tableau destiné à être lu plutôt que calculé, écrivez la définition avec lui : Un nombre et sa définition voyagent ensemble, sinon la dispute mensuelle sur le dénominateur recommence.Les trois renversements, en un seul endroit
pandas R / dplyr Valeur manquante dans mean()ignorée en silence renvoie NAjusqu'àna.rmClé de groupe manquante écartée conservée comme groupe à part Catégorie inutilisée écartée par observed=Trueconservée par table(), écartée parcount()Notes du présentateur
Aucun n'est meilleur. Chacun est un pari différent sur ce que le silence doit signifier, et savoir dans quel pari on se trouve constitue l'essentiel du métier.Ce qui vient ensuite
- Le tableau agrège correctement et les deux moitiés de chaque taux proviennent d'un seul appel.
Notes du présentateur
Le tableau agrège correctement et les deux moitiés de chaque taux proviennent d'un seul appel. L'unité suivante restructure :pivot_longer()sur le groupe répété aplati sous lequel arrive un export CommCare ou Kobo, puis la fonction qui fait tourner tout le nettoyage au trimestre suivant.