cassionData Analysis

Back to the lessonLesson 3 of 8Who is a case

The case definitions, and the clause everyone drops

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 / 20

    What this lesson covers

    • The definitions
    • The implementation that is wrong
    • The implementation that is right
    • Check that the parts sum to the whole
    • The MUAC definitions, on the register
    • What a definition does not say
    • What comes next
    Speaker notes
    Severe, moderate and global acute malnutrition, the cut-offs the sector agreed on, and the oedema clause that makes every "count below the threshold" implementation wrong.
  2. Slide 2 / 20

    The definitions

    TermWeight-for-height zMUACOedema
    SAM — severe acute malnutritionbelow -3below 115 mmpresent
    MAM — moderate acute malnutrition-3 to below -2115 to below 125 mm—
    GAM — global acute malnutritionbelow -2below 125 mmpresent
    Speaker notes
    Three terms, and they nest.
  3. Slide 3 / 20

    The definitions

    • GAM is SAM plus MAM — It is not a separate condition; it is the total burden of acute malnutrition, and it is the…
    • Each row is a complete definition on its own — A child is SAM by weight-for-height, or by MUAC, or by oedema — the…
    • The oedema column is an OR, not an AND — A child with bilateral pitting oedema is severe whatever their measurements say
    Speaker notes
    GAM is SAM plus MAM. It is not a separate condition; it is the total burden of acute malnutrition, and it is the figure the IPC phases and the 15% emergency threshold are defined against. Two structural points before any code. Each row is a complete definition on its own. A child is SAM by weight-for-height, or by MUAC, or by oedema — the criteria are alternatives, not requirements. Lesson 4 is entirely about how far the first two disagree. The oedema column is an OR, not an AND. A child with bilateral pitting oedema is severe whatever their measurements say. That clause is one term in a boolean expression and it is the term most often left out.
  4. Slide 4 / 20

    The implementation that is wrong — In Python

    # WRONG: the definition everybody writes first
    sam_wrong = (smart["whz"] < -3).sum()
  5. Slide 5 / 20

    The implementation that is wrong — In R

    # WRONG
    sum(smart$whz < -3, na.rm = TRUE)
    Speaker notes
    It is wrong in two ways at once. It drops the oedematous children, and na.rm or a null-propagating comparison silently drops the children with no z-score — so both the numerator and the denominator are quietly different from what the label claims.
  6. Slide 6 / 20

    The implementation that is right — In Python

    import pandas as pd
    
    analysable = smart[smart["whz"].between(-5, 5)].copy()
    oedema = analysable["oedema"] == True
    
    analysable["sam"] = (analysable["whz"] < -3) | oedema
    analysable["mam"] = (analysable["whz"].between(-3, -2, inclusive="left")) & ~oedema
    analysable["gam"] = analysable["sam"] | analysable["mam"]
    
    n = len(analysable)
    for label in ["sam", "mam", "gam"]:
        print(f"{label.upper():4} {analysable[label].sum():>4} / {n}  "
              f"{analysable[label].mean():.1%}")
  7. Slide 7 / 20

    The implementation that is right — In R

    analysable <- smart |> filter(between(whz, -5, 5))
    
    analysable <- analysable |>
      mutate(sam = whz < -3 | oedema,
             mam = whz >= -3 & whz < -2 & !oedema,
             gam = sam | mam)
    
    analysable |> summarise(across(c(sam, mam, gam), list(n = sum, rate = mean)), n = n())
  8. Slide 8 / 20

    The implementation that is right

    • MAM excludes oedema explicitly — An oedematous child whose z-score falls in the moderate band is severe, not moderate,…
    • The bounds are half-open — -3 <= z < -2
    • The denominator is stated — 852, not 930 — the difference is children with no computable z-score and children outside…
    Speaker notes
    852 analysable children: GAM 14.9%, SAM 3.8%. Three details in that code are load-bearing. MAM excludes oedema explicitly. An oedematous child whose z-score falls in the moderate band is severe, not moderate, and without the & ~oedema they would be counted in both — so SAM plus MAM would exceed GAM. The bounds are half-open. -3 <= z < -2. A child at exactly -3.0 is severe. Getting this wrong moves a handful of children and is the kind of thing two analysts discover they disagree on at the worst moment. The denominator is stated. 852, not 930 — the difference is children with no computable z-score and children outside the flagging bounds, and lesson 2 required you to report those three groups separately.
  9. Slide 9 / 20

    Check that the parts sum to the whole — In Python

    assert (analysable["sam"] & analysable["mam"]).sum() == 0, "a child is both"
    assert analysable["gam"].sum() == analysable["sam"].sum() + analysable["mam"].sum()
  10. Slide 10 / 20

    Check that the parts sum to the whole — In R

    stopifnot(sum(analysable$sam & analysable$mam) == 0,
              sum(analysable$gam) == sum(analysable$sam) + sum(analysable$mam))
    Speaker notes
    Two assertions, and they catch the oedema mistake, the bound mistake and any future edit that breaks the nesting. Run them every time.
  11. Slide 11 / 20

    The MUAC definitions, on the register — In Python

    muac = pd.read_csv("muac-screening-artibonite-2024.v1.csv")
    measured = muac[muac["muac_mm"].notna()].copy()
    oed = measured["oedema"] == True
    
    measured["sam"] = (measured["muac_mm"] < 115) | oed
    measured["gam"] = (measured["muac_mm"] < 125) | oed
    
    print(f"n = {len(measured):,}  GAM {measured['gam'].mean():.1%}  "
          f"SAM {measured['sam'].mean():.1%}")
    Speaker notes
    The screening register has MUAC and oedema and no weight or height, so it supports the MUAC-based definitions only.
  12. Slide 12 / 20

    The MUAC definitions, on the register — In R

    muac |>
      filter(!is.na(muac_mm)) |>
      summarise(n = n(),
                gam = mean(muac_mm < 125 | oedema),
                sam = mean(muac_mm < 115 | oedema))
  13. Slide 13 / 20

    The MUAC definitions, on the register

    • Name the measure in the indicator — gam_muac_percent and gam_whz_percent are different indicators that both get…
    Speaker notes
    Name the measure in the indicator. gam_muac_percent and gam_whz_percent are different indicators that both get called "GAM", and the indicator design course's rule about putting the measure in the name is not pedantry here — the next lesson shows the two disagreeing on three-quarters of severe cases.
  14. Slide 14 / 20

    What a definition does not say

    • Age — The definitions apply to children 6 to 59 months
    Speaker notes
    Three things the case definition deliberately leaves out, each of which someone will assume. Age. The definitions apply to children 6 to 59 months. Below six months the standards and the case definitions are different; above 59 months they do not apply at all. Check the age range before classifying.
  15. Slide 15 / 20

    What a definition does not say — In Python

    out_of_scope = ~analysable["age_months"].between(6, 59)
    print(f"{out_of_scope.sum()} children outside 6-59 months")
  16. Slide 16 / 20

    What a definition does not say — In R

    sum(!between(analysable$age_months, 6, 59), na.rm = TRUE)
  17. Slide 17 / 20

    What a definition does not say

    • Admission — A case definition says who is malnourished
    • Severity within severe — SAM with complications needs inpatient care; SAM without needs outpatient
    Speaker notes
    Admission. A case definition says who is malnourished. Whether they are admitted depends on the programme's protocol, which may use one criterion, both, or MUAC only for community screening and weight-for-height at the site. The register's admission_criterion records what the site entered, not everything the child met. Severity within severe. SAM with complications needs inpatient care; SAM without needs outpatient. The definition does not distinguish them, and the appetite test and clinical signs that do are not in an anthropometric dataset.
  18. Slide 18 / 20

    What a definition does not say

    A case definition is a classification rule, not a treatment decision. Confusing the two produces a caseload figure that does not match any programme's admissions and an argument nobody can resolve from the data.
  19. Slide 19 / 20

    What comes next

    • You can classify a child by either measure.
    Speaker notes
    You can classify a child by either measure. The next lesson puts the two measures on the same children and finds that they disagree on three-quarters of severe cases — and that the disagreement has a cause you can name in one number.
  20. Slide 20 / 20

    Where this goes next

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