cassionData Analysis

Back to the lessonLesson 7 of 8The design and the fit

Two coefficients cross the line and one crosses back

The same deck as the downloads, rendered as a page. Start the slideshow to present it full screen — arrow keys or a click advance one slide, Escape leaves.

Slides · PDFSlides · PowerPoint

  1. Slide 1 / 26

    What this lesson covers

    • The design the sample was drawn under
    • What the weights do to an estimate
    • The same model, weighted and not
    • Weights, clusters and strata are three separate things
    • When to leave the weights out
    • Report it whole
    • What comes next
    Speaker notes
    The rural-remote stratum holds 11% of households and a third of the interviews. Fit the model unweighted and livestock livelihoods look like a significant risk factor; weight it and they stop being one, while household size and returnee status start.
  2. Slide 2 / 26

    The design the sample was drawn under — In Python

    import pandas as pd
    
    survey = pd.read_csv("household-survey-2025.v1.csv")
    frame = pd.read_csv("household-survey-frame-2025.v1.csv")
    
    print(frame.groupby("stratum")["households"].sum())
    print(survey.groupby("stratum").size())
  3. Slide 3 / 26

    The design the sample was drawn under — In R

    library(dplyr)
    frame |> summarise(households = sum(households), .by = stratum)
    survey |> count(stratum)
  4. Slide 4 / 26

    The design the sample was drawn under

    StratumHouseholds in frameShareInterviewsShare
    Rural accessible28,95851.3%33733.8%
    Urban21,27037.7%31631.7%
    Rural remote6,20011.0%34334.4%
  5. Slide 5 / 26

    The design the sample was drawn under

    • Rural remote is 11.0% of the population and 34.4% of the sample — That is a deliberate design choice — the survey…
    Speaker notes
    Rural remote is 11.0% of the population and 34.4% of the sample. That is a deliberate design choice — the survey course explains why you over-sample a small stratum you need estimates for — and it means every unweighted number from this file describes a population that does not exist.
  6. Slide 6 / 26

    What the weights do to an estimate — In Python

    stratum_households = frame.groupby("stratum")["households"].sum()
    base_weight = stratum_households / (25 * 14)
    interviewed = frame[frame["selected"]].set_index("ea_id")["households_interviewed"]
    
    survey["weight"] = (survey["stratum"].map(base_weight)
                        * 14 / survey["ea_id"].map(interviewed))
    assert abs(survey["weight"].sum() - frame["households"].sum()) < 1
    
    unweighted = survey["food_insecure"].mean()
    weighted = np.average(survey["food_insecure"], weights=survey["weight"])
    print(f"unweighted {unweighted:.1%}   weighted {weighted:.1%}")
  7. Slide 7 / 26

    What the weights do to an estimate — In R

    survey <- survey |>
      mutate(weight = base_weight[stratum] * 14 / households_interviewed)
    
    c(unweighted = mean(survey$food_insecure),
      weighted   = weighted.mean(survey$food_insecure, survey$weight))
  8. Slide 8 / 26

    What the weights do to an estimate

    • 32.8% unweighted, 29.1% weighted — Rural remote has the highest food insecurity (46.4%), and over-representing it by…
    • A regression fitted on this file without weights inherits exactly that problem — and it is not fixed by adding…
    Speaker notes
    32.8% unweighted, 29.1% weighted. Rural remote has the highest food insecurity (46.4%), and over-representing it by three times pulls the national figure up by 3.7 points. A regression fitted on this file without weights inherits exactly that problem, and it is not fixed by adding stratum as a covariate — that changes the question from "what is the association in the population" to "what is it within strata". Both are legitimate; only one is what a national estimate means.
  9. Slide 9 / 26

    The same model, weighted and not — In Python

    import statsmodels.api as sm
    import statsmodels.formula.api as smf
    
    FORMULA = ("food_insecure ~ improved_water_source + displacement_status"
               " + main_livelihood + household_size")
    
    plain = smf.glm(FORMULA, data=d, family=sm.families.Binomial()).fit(
        cov_type="cluster", cov_kwds={"groups": d["ea_id"]})
    
    weighted = smf.glm(FORMULA, data=d, family=sm.families.Binomial(),
                       freq_weights=d["weight"]).fit(
        cov_type="cluster", cov_kwds={"groups": d["ea_id"]})
  10. Slide 10 / 26

    The same model, weighted and not — In R

    library(survey)
    
    design <- svydesign(ids = ~ea_id, strata = ~stratum, weights = ~weight,
                        data = survey, nest = TRUE)
    svyglm(food_insecure ~ improved_water_source + displacement_status +
             main_livelihood + household_size, design = design,
           family = quasibinomial())
  11. Slide 11 / 26

    The same model, weighted and not

    TermUnweighted ORWeighted ORMoves?
    Improved water source0.75 (0.55–1.03)0.74 (0.51–1.08)—
    Displacement: returnee0.56 (0.25–1.26)0.39 (0.15–0.97)becomes significant
    Livelihood: farming1.55 (1.03–2.34)1.69 (1.04–2.75)—
    Livelihood: livestock1.51 (1.04–2.18)1.26 (0.73–2.18)stops being significant
    Livelihood: salaried0.41 (0.22–0.77)0.45 (0.24–0.87)—
    Household size1.04 (0.98–1.11)1.08 (1.01–1.16)becomes significant
  12. Slide 12 / 26

    The same model, weighted and not

    • Three coefficients change which side of the line they sit on, in both directions — Weighting is not a correction that…
    • Livestock livelihoods are concentrated in the over-sampled remote stratum — Unweighted, they carry a third of the…
    Speaker notes
    Three coefficients change which side of the line they sit on, in both directions. Weighting is not a correction that makes everything weaker or everything stronger — it re-weights which households the association is estimated from, and the answer moves wherever those households differ. Livestock livelihoods are concentrated in the over-sampled remote stratum. Unweighted, they carry a third of the sample's influence; weighted, they carry their real 11%, and the association thins out to nothing.
  13. Slide 13 / 26

    Weights, clusters and strata are three separate things

    Design featureFixesIf you omit it
    WeightsThe estimateEstimates describe the sample, not the population
    ClustersThe standard errorStandard errors too small, as in the last lesson
    StrataThe standard errorStandard errors slightly too large — the conservative error
    Speaker notes
    They arrive together and they do three different jobs, and a model can easily get one right and the other two wrong.
  14. Slide 14 / 26

    Weights, clusters and strata are three separate things

    • Weights change the coefficient; clusters and strata change its interval — That is the same distinction as…
    Speaker notes
    Weights change the coefficient; clusters and strata change its interval. That is the same distinction as adjustment-versus-clustering from lesson 2, arriving from a different direction, and it is the one to hold onto.
  15. Slide 15 / 26

    Weights, clusters and strata are three separate things — In Python

    print(f"clusters: {d['ea_id'].nunique()} enumeration areas")
    print(f"strata:   {d['stratum'].nunique()}")
    print(f"weights:  {d['weight'].min():.1f} to {d['weight'].max():.1f}")
  16. Slide 16 / 26

    Weights, clusters and strata are three separate things — In R

    # survey::svydesign wants all three; a glm with weights= handles only one.
  17. Slide 17 / 26

    Weights, clusters and strata are three separate things

    • glm(..., weights=) is not survey-weighted regression — It applies the weights and computes standard errors as though…
    Speaker notes
    glm(..., weights=) is not survey-weighted regression. It applies the weights and computes standard errors as though every observation were independent and the weights were frequencies. Use survey::svyglm in R, and in Python pass both freq_weights and a cluster covariance — or accept that the interval is wrong and say so.
  18. Slide 18 / 26

    When to leave the weights out

    • A within-stratum question — "Among rural remote households, does an improved water source go with lower food…
    • A model whose covariates include everything the weights are built from — If stratum and selection probability are fully…
    Speaker notes
    Two cases, and neither is "the weights made my result go away". A within-stratum question. "Among rural remote households, does an improved water source go with lower food insecurity?" is a question about that stratum, and the design weight within a stratum is nearly constant anyway. A model whose covariates include everything the weights are built from. If stratum and selection probability are fully captured by the covariates, the weighted and unweighted estimates answer the same question and the unweighted one is more precise. Check it rather than assume it: fit both, and if they differ materially the covariates did not capture the design.
  19. Slide 19 / 26

    When to leave the weights out — In Python

    print(f"unweighted {plain.params['main_livelihood[T.livestock]']:.3f}")
    print(f"weighted   {weighted.params['main_livelihood[T.livestock]']:.3f}")
  20. Slide 20 / 26

    When to leave the weights out — In R

    # A large gap between the two is evidence the design is not in the model.
  21. Slide 21 / 26

    When to leave the weights out

    • A large difference between the weighted and unweighted fit is itself diagnostic — and it is the check to run before…
    Speaker notes
    A large difference between the weighted and unweighted fit is itself diagnostic, and it is the check to run before deciding the weights are optional.
  22. Slide 22 / 26

    Report it whole — Example (cont.)

    Food insecurity, household survey 2025
    
      976 households with complete covariates (of 996 interviewed),
      75 enumeration areas, 3 strata.
      Survey-weighted logistic regression; weights sum to 56,428 households,
      which is the frame total. Standard errors account for clustering by
      enumeration area and for stratification.
    
      Weighted prevalence      29.1%   (unweighted 32.8%)
    
      Adjusted odds ratios (weighted):
        Improved water source          0.74   95% CI 0.51 to 1.08
        Returnee household             0.39   95% CI 0.15 to 0.97
        Farming livelihood             1.69   95% CI 1.04 to 2.75
        Livestock livelihood           1.26   95% CI 0.73 to 2.18
        Salaried livelihood            0.45   95% CI 0.24 to 0.87
  23. Slide 23 / 26

    Report it whole — Example (cont.)

        Household size, per person     1.08   95% CI 1.01 to 1.16
    
      The unweighted model makes livestock livelihoods significant (OR 1.51,
      95% CI 1.04 to 2.18) and household size not. The rural remote stratum is
      11% of households and 34% of interviews, and livestock is concentrated
      there; the unweighted result is an artefact of the sampling design.
    
      Odds ratios are reported because food insecurity is 29% and the ratios are
      moderate; the weighted risk difference for salaried livelihoods is -14.2
      points against the observed mix of livelihoods, which is the number in
      the summary.
  24. Slide 24 / 26

    Report it whole

    • The paragraph naming the artefact is what a reviewer will check first — and writing it yourself is better than having…
    Speaker notes
    The paragraph naming the artefact is what a reviewer will check first, and writing it yourself is better than having it found.
  25. Slide 25 / 26

    What comes next

    • Every model so far has been fitted and read.
    Speaker notes
    Every model so far has been fitted and read. The last lesson fits one that explains three per cent of its outcome, does not improve on guessing, and is the most useful result in its report — because what it fails to predict is the operational answer.
  26. Slide 26 / 26

    Where this goes next

    Read the full lesson, with runnable code Back to the lesson