Leçon 2 sur 8
Unité · Calculez-le avant d'y croire
Les trente-sept ménages que le remplissage par zéro déclasserait
Compléter par des zéros une échelle de la faim incomplète déplace la prévalence de trois dixièmes de point et peut mal classer chacun des trente-sept ménages concernés. Lequel des deux compte dépend de si votre production est un pourcentage ou une liste.
Deux instruments de plus, deux règles de plus
L’échelle de la faim dans le ménage et l’indice réduit des stratégies de survie
accompagnent le score de consommation alimentaire dans presque toute enquête de
sécurité alimentaire, et chacun porte une règle de cotation qu’un sum() naïf
casse d’une façon différente.
| Instrument | Ce qu’il demande | La règle qui saute |
|---|---|---|
| ÉFM | Trois questions sur la privation de nourriture, cotées 0–2 chacune | Valide seulement si les trois sont renseignées |
| ICSR | Cinq comportements, jours sur les sept derniers, pondérés | Les pondérations ne valent pas toutes 1, et la cinquième vaut 3 |
L’échelle de la faim dans le ménage
Trois questions, délibérément peu nombreuses, délibérément sévères : n’y avait-il aucune nourriture d’aucune sorte dans la maison, quelqu’un s’est-il couché en ayant faim, quelqu’un est-il resté un jour et une nuit entiers sans manger. Chacune est cotée 0 pour jamais, 1 pour rarement ou parfois, 2 pour souvent.
import pandas as pd
survey = pd.read_csv("food-security-survey-2024.v1.csv")
HHS = ["hhs_no_food_in_house", "hhs_sleep_hungry",
"hhs_day_and_night_without_eating"]
complete = survey[HHS].notna().all(axis=1)
score = survey.loc[complete, HHS].sum(axis=1)
bands = pd.cut(score, [-1, 1, 3, 6],
labels=["little or none", "moderate", "severe"])
print(f"complete: {complete.sum()} of {len(survey)}")
print((bands.value_counts(normalize=True) * 100).round(1))
library(dplyr)
hhs <- c("hhs_no_food_in_house", "hhs_sleep_hungry",
"hhs_day_and_night_without_eating")
survey |>
filter(if_all(all_of(hhs), ~ !is.na(.x))) |>
mutate(score = rowSums(across(all_of(hhs))),
band = cut(score, c(-1, 1, 3, 6),
labels = c("little or none", "moderate", "severe"))) |>
count(band) |> mutate(share = n / sum(n))
| Catégorie | Ménages | Part |
|---|---|---|
| Faim faible ou nulle (0–1) | 1 186 | 57,2 % |
| Modérée (2–3) | 564 | 27,2 % |
| Sévère (4–6) | 325 | 15,7 % |
2 075 ménages sur 2 112 ont répondu aux trois questions. Les trente-sept qui ne l’ont pas fait sont les intéressants.
Ce que coûte réellement le remplissage par zéro
L’intuition est que supprimer les réponses incomplètes fait perdre de l’information, donc qu’il faut combler le trou par un zéro et les garder. Essayez, et mesurez.
zero_filled = survey[HHS].fillna(0).sum(axis=1)
naive = pd.cut(zero_filled, [-1, 1, 3, 6],
labels=["little or none", "moderate", "severe"])
print((naive.value_counts(normalize=True) * 100).round(1))
survey |>
mutate(score = rowSums(across(all_of(hhs)), na.rm = TRUE)) |>
count(band = cut(score, c(-1, 1, 3, 6)))
| Cas complets | Complété par zéro | |
|---|---|---|
| Faible ou nulle | 57,2 % | 57,5 % |
| Modérée | 27,2 % | 26,9 % |
| Sévère | 15,7 % | 15,5 % |
Trois dixièmes de point de pourcentage. Sur une prévalence, le remplissage par zéro est ici pratiquement inoffensif, et si vous vous arrêtez au tableau vous en conclurez que cela n’a pas d’importance.
Regardez maintenant les ménages plutôt que le pourcentage.
partial = survey.loc[~complete, HHS]
print(partial.sum(axis=1).value_counts().sort_index())
survey |> filter(if_any(all_of(hhs), is.na)) |>
mutate(observed = rowSums(across(all_of(hhs)), na.rm = TRUE)) |> count(observed)
Vingt-neuf des trente-sept obtiennent 0 ou 1 sur les questions auxquelles ils ont répondu, si bien que le remplissage par zéro les classe en faim faible ou nulle. La question sans réponse vaut jusqu’à 2 points. Un ménage à 1 avec une question manquante peut être à 1 ou à 3 — faim faible ou modérée — et rien dans les données ne tranche.
Le coût du remplissage par zéro dépend donc entièrement de ce que produit l’analyse.
- Si la production est une prévalence, le dommage vaut trois dixièmes de point et il faut dire que vous avez complété par zéro puis passer à la suite.
- Si la production est une liste de ciblage, vous venez de dire à trente-sept ménages qu’ils sont en sécurité alimentaire sur la foi d’une question que personne n’a posée.
Nommez la production avant de choisir la règle. C’est la même décision que le dénominateur du taux de guérison PCIMA et que le taux de fonctionnalité des points d’eau : le choix défendable n’est pas une propriété des données, c’est une propriété de la décision que le nombre alimente.
L’indice réduit des stratégies de survie
Cinq comportements, jours sur les sept derniers, et les pondérations sont tout l’enjeu.
RCSI = {
"rcsi_less_preferred_food": 1,
"rcsi_borrowed_food": 2,
"rcsi_limit_portion_size": 1,
"rcsi_restrict_adult_consumption": 3,
"rcsi_reduce_meal_numbers": 1,
}
rcsi = sum(survey[column] * weight for column, weight in RCSI.items())
print(f"median {rcsi.median():.0f}, mean {rcsi.mean():.1f}, max {rcsi.max():.0f}")
print(f"rCSI 19 or above: {(rcsi >= 19).mean():.1%}")
rcsi_weights <- c(rcsi_less_preferred_food = 1, rcsi_borrowed_food = 2,
rcsi_limit_portion_size = 1,
rcsi_restrict_adult_consumption = 3,
rcsi_reduce_meal_numbers = 1)
Médiane 19, moyenne 19,5, et 50,9 % à 19 ou plus. La pondération de 3 sur restreindre la consommation des adultes pour que les enfants mangent n’est pas arbitraire — c’est le comportement le plus prédictif d’une dégradation, et une somme non pondérée l’enterrerait parmi quatre comportements pondérés 1.
Deux choses régulièrement mal comprises sur l’ICSR.
Il n’a pas de seuil universel. Contrairement au SCA, ses seuils sont propres au contexte et généralement fixés face à la distribution de la même population. Un rapport citant « ICSR supérieur à 19 » comme si 19 était un standard a emprunté un nombre à l’analyse d’un autre pays.
Il monte avant que la consommation ne baisse, et il peut aussi baisser dans une crise, quand un ménage a épuisé les stratégies. Un ICSR qui baisse à côté d’un SCA qui baisse est une plus mauvaise nouvelle qu’un ICSR qui monte.
Trois instruments, trois échantillons analysables
denominators = pd.DataFrame({
"instrument": ["Food Consumption Score", "Household Hunger Scale",
"reduced Coping Strategy Index"],
"analysable": [1989, 2075, 2112],
"excluded": [123, 37, 0],
"rule": ["all eight groups answered", "all three questions answered",
"complete in this file"],
})
print(denominators)
# Print this before the results, every time.
Trois nombres sur trois dénominateurs, et aucun ne vaut 2 112. L’écart est assez petit pour être invisible dans un tableau et assez grand pour compter quand quelqu’un soustrait deux de vos pourcentages.
La suite
La consommation et la faim disent ce qu’un ménage vit. Ni l’une ni l’autre ne dit ce qu’il fait pour y répondre, et la leçon suivante porte sur le module qui le dit — où la règle de cotation n’est pas du tout une somme.