cassionAnalyse de données

Retour à la leçonLeçon 5 sur 8Estimer correctement

Déclarez le plan une seule fois

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.

Diapositives · PDFDiapositives · PowerPoint

  1. Diapositive 1 / 21

    Ce que couvre cette leçon

    • Cessez de porter le plan à la main
    • L'objet de plan sous R
    • La même chose en Python
    • L'approximation par grappe ultime
    • Les quatre façons d'obtenir une simple moyenne par accident
    • Des estimations autres que des proportions
    • Le plan du sous-échantillon
    • Écrivez le plan à côté des estimations
    • La suite
    Notes du présentateur
    Un objet de plan, et toute estimation ultérieure hérite des pondérations, des strates et des grappes. Le paquet survey de R, l'arithmétique équivalente en Python, et les quatre erreurs qui produisent en silence une simple moyenne.
  2. Diapositive 2 / 21

    Cessez de porter le plan à la main

    • Tout ce qui précède a été calculé explicitement, et c'était voulu — il faut savoir ce qu'est l'arithmétique.
    Notes du présentateur
    Tout ce qui précède a été calculé explicitement, et c'était voulu — il faut savoir ce qu'est l'arithmétique. À partir d'ici, le plan doit être déclaré une fois et hérité, car l'alternative consiste à penser à appliquer pondérations, strates et grappes à chaque estimation d'un script de cinquante lignes, et l'estimation que vous oublierez est celle qui ira dans le résumé.
  3. Diapositive 3 / 21

    L'objet de plan sous R — En R

    library(survey)
    
    design <- svydesign(
      ids     = ~ea_id,      # the primary sampling unit
      strata  = ~stratum,    # the stratification
      weights = ~weight,     # the weight built in lesson 2
      data    = survey,
      nest    = TRUE         # cluster ids are nested within strata
    )
    
    design
  4. Diapositive 4 / 21

    L'objet de plan sous R

    • ids est l'unité primaire de sondage — la zone de dénombrement, non le ménage. Passer ~household_id ici est…
    • strata retire la variance inter-strates, qui est le gain mesuré à la leçon précédente.
    • weights rend l'estimation ponctuelle sans biais.
    • nest = TRUE indique au paquet que les identifiants de zone ne sont uniques qu'à l'intérieur d'une strate.…
    Notes du présentateur
    Quatre arguments et chacun porte. Ensuite, chaque estimation sort du plan.
  5. Diapositive 5 / 21

    L'objet de plan sous R — En R

    svymean(~I(food_insecure == "true"), design, deff = TRUE)
    svytotal(~I(food_insecure == "true"), design)
    svyby(~I(food_insecure == "true"), ~stratum, design, svymean, vartype = c("se", "ci"))
    svyciprop(~I(food_insecure == "true"), design, method = "logit")
    Notes du présentateur
    svyby est le cheval de trait — n'importe quelle estimation, par n'importe quel regroupement, avec le plan propagé. Et svyciprop est ce qu'il faut pour une proportion : la leçon suivante explique pourquoi l'intervalle de svymean a la mauvaise forme près de 0 et de 1.
  6. Diapositive 6 / 21

    La même chose en Python — En Python (suite)

    import numpy as np
    import pandas as pd
    
    
    class SurveyDesign:
        """Stratified two-stage design, ultimate-cluster variance."""
    
        def __init__(self, data, ids, strata, weights):
            self.data, self.ids, self.strata, self.weights = data, ids, strata, weights
    
        def mean(self, indicator):
            d = self.data
            y = indicator(d).astype(float)
            w = d[self.weights]
            p = np.average(y, weights=w)
    
    Notes du présentateur
    Python n'a pas d'équivalent de survey sur lequel ce secteur se soit fixé, si bien que les exemples calculent l'estimateur directement. C'est un coût et aussi un avantage — l'arithmétique reste visible.
  7. Diapositive 7 / 21

    La même chose en Python — En Python (suite)

            variance, total_w = 0.0, w.sum()
            for _, stratum in d.groupby(self.strata):
                residual = stratum[self.weights] * (indicator(stratum).astype(float) - p)
                totals = residual.groupby(stratum[self.ids]).sum()
                n = len(totals)
                if n < 2:
                    continue
                variance += n / (n - 1) * ((totals - totals.mean()) ** 2).sum()
            se = np.sqrt(variance) / total_w
    
            srs = np.sqrt(p * (1 - p) / len(d))
            return {"estimate": p, "se": se, "deff": (se / srs) ** 2,
                    "ci_low": p - 1.96 * se, "ci_high": p + 1.96 * se}
    
    
    design = SurveyDesign(survey, ids="ea_id", strata="stratum", weights="weight")
  8. Diapositive 8 / 21

    La même chose en Python — En Python (suite)

    print(design.mean(lambda d: d["food_insecure"] == "true"))
  9. Diapositive 9 / 21

    La même chose en Python — En R

    # The R equivalent of the whole class above:
    svymean(~I(food_insecure == "true"), design, deff = TRUE)
    Notes du présentateur
    La classe Python fait trente lignes et l'appel R une seule. Cette asymétrie est réelle et c'est pourquoi l'analyse d'enquêtes se fait d'ordinaire en R dans ce secteur. Employez R pour l'estimation d'enquête quand vous avez le choix ; la voie Python est pour les équipes qui ne l'ont pas, et pour comprendre ce que fait l'appel R.
  10. Diapositive 10 / 21

    L'approximation par grappe ultime

    • Les deux implémentations emploient le même raccourci, et il vaut la peine de le nommer car il ressemble à une simplification sans en être une.
    Notes du présentateur
    Les deux implémentations emploient le même raccourci, et il vaut la peine de le nommer car il ressemble à une simplification sans en être une. La variance se calcule à partir des totaux des unités primaires de sondage, en ignorant entièrement le second degré. C'est exact lorsque le premier degré est tiré avec remise, et légèrement conservateur sinon — cela surestime très légèrement la variance en ignorant la correction de population finie au second degré. Être légèrement conservateur est le bon sens d'erreur, et c'est pourquoi tous les grands paquets font cela par défaut. survey l'appelle l'approximation par grappe ultime, et tous les rapports EDS aussi.
  11. Diapositive 11 / 21

    Les quatre façons d'obtenir une simple moyenne par accident

    • Passer le ménage comme grappe — ids = ~household_id dit que chaque ménage est sa propre unité primaire, donc qu'il…
    • Oublier les pondérations — svydesign(..., weights = NULL) donne à chaque ménage le même poids, ce qui est le 32,8 %…
    • Filtrer le tableau au lieu de sous-ensembler le plan — Celle-ci est subtile et fréquente
    Notes du présentateur
    Chacune produit un nombre d'allure correcte qui est une estimation de sondage aléatoire simple. Passer le ménage comme grappe. ids = ~household_id dit que chaque ménage est sa propre unité primaire, donc qu'il n'y a pas de mise en grappes à prendre en compte, et l'erreur type s'effondre. Oublier les pondérations. svydesign(..., weights = NULL) donne à chaque ménage le même poids, ce qui est le 32,8 % de la leçon 1. Filtrer le tableau au lieu de sous-ensembler le plan. Celle-ci est subtile et fréquente.
  12. Diapositive 12 / 21

    Les quatre façons d'obtenir une simple moyenne par accident — En R

    # WRONG: the design object no longer knows about the dropped strata
    rural <- svydesign(ids = ~ea_id, strata = ~stratum, weights = ~weight,
                       data = filter(survey, stratum != "urban"), nest = TRUE)
    
    # RIGHT
    rural <- subset(design, stratum != "urban")
  13. Diapositive 13 / 21

    Les quatre façons d'obtenir une simple moyenne par accident — En Python

    # Same rule: subset the design, keeping the full strata structure in view
    rural = SurveyDesign(survey[survey["stratum"] != "urban"],
                         ids="ea_id", strata="stratum", weights="weight")
  14. Diapositive 14 / 21

    Les quatre façons d'obtenir une simple moyenne par accident

    • Calculer sur un tableau joint — Joignez l'enquête à quoi que ce soit en un-à-plusieurs et les pondérations deviennent…
    Notes du présentateur
    Sous-ensembler un plan préserve la structure des strates et des grappes pour l'estimation de variance. Le reconstruire depuis un tableau filtré jette les zones sans ménage restant, ce qui change les degrés de liberté et peut produire en silence une strate à une seule grappe — où la contribution à la variance est indéfinie et discrètement écartée. Calculer sur un tableau joint. Joignez l'enquête à quoi que ce soit en un-à-plusieurs et les pondérations deviennent fausses, car un ménage apparaît plusieurs fois. Agrégez au ménage avant d'estimer : c'est la leçon sur la granularité du cours de jointures qui revient dans un autre décor.
  15. Diapositive 15 / 21

    Des estimations autres que des proportions — En R

    svymean(~household_size, design, na.rm = TRUE)
    svytotal(~I(food_insecure == "true"), design)
    svyquantile(~minutes_to_water, design, quantiles = c(0.5, 0.9), na.rm = TRUE)
    svyratio(~I(food_insecure == "true"), ~I(children_under5 > 0), design)
  16. Diapositive 16 / 21

    Des estimations autres que des proportions — En Python

    print(design.mean(lambda d: d["household_size"] > 7))
    Notes du présentateur
    Deux remarques. Un total pondéré est l'estimation que l'on veut le plus souvent et qu'on ne peut le plus souvent pas obtenir, car elle exige des pondérations à l'échelle de la population — les pondérations normalisées de la leçon 2 donneraient un total de 996. Et na.rm = TRUE sur une moyenne d'enquête est une décision et non une commodité : cela suppose que les ménages manquants ressemblent aux ménages observés de leur strate, hypothèse identique à celle de l'ajustement pour non-réponse, et à énoncer une fois pour les deux.
  17. Diapositive 17 / 21

    Le plan du sous-échantillon — En R

    children <- subset(design, !is.na(child_muac_mm))
    children <- update(children, child_weight = weight * children_under5)
    
    child_design <- svydesign(ids = ~ea_id, strata = ~stratum,
                              weights = ~child_weight,
                              data = subset(survey, !is.na(child_muac_mm)), nest = TRUE)
    
    svyciprop(~I(child_muac_mm < 125), child_design, method = "logit")
    Notes du présentateur
    Les enfants mesurés forment un sous-échantillon avec sa propre pondération, et ils exigent leur propre objet de plan — non un filtre sur celui des ménages.
  18. Diapositive 18 / 21

    Le plan du sous-échantillon — En Python

    measured = survey[survey["child_muac_mm"].notna()].copy()
    measured["child_weight"] = measured["weight"] * measured["children_under5"]
    
    child_design = SurveyDesign(measured, ids="ea_id", strata="stratum",
                                weights="child_weight")
    print(child_design.mean(lambda d: d["child_muac_mm"] < 125))
    Notes du présentateur
    Les grappes sont les mêmes zones, donc la mise en grappes s'applique toujours. Seuls la pondération et la population changent.
  19. Diapositive 19 / 21

    Écrivez le plan à côté des estimations — Exemple

    Design           Stratified two-stage cluster
    Strata           urban, rural-accessible, rural-remote
    PSU              enumeration area (75 sampled, 25 per stratum)
    Stage 1          PPS, size measure = households at frame listing
    Stage 2          SRS, 14 households per area
    Weights          base = M_h / (25 * 14), non-response adjusted within area
    Variance         ultimate cluster, Taylor linearisation
    Software         R survey 4.x / equivalent direct computation in Python
    Notes du présentateur
    Sept lignes. Tout lecteur peut désormais reproduire vos erreurs types, et tout relecteur peut voir en dix secondes si vous avez fait les choses correctement — ce qu'on ne peut pas dire de la plupart des annexes d'enquête.
  20. Diapositive 20 / 21

    La suite

    • L'objet de plan suppose que tous les ménages tirés ont été enquêtés et que toutes les zones tirées ont été visitées.
    Notes du présentateur
    L'objet de plan suppose que tous les ménages tirés ont été enquêtés et que toutes les zones tirées ont été visitées. Ni l'un ni l'autre n'est vrai ici. La leçon suivante traite les 54 ménages non enquêtés et les deux zones qu'il a fallu remplacer.
  21. Diapositive 21 / 21

    La suite

    Lire la leçon complète, avec le code exécutable Retour à la leçon