cassionData Analysis

Lesson 4 of 8

Unit · Who is a case

Where the two criteria disagree

468 children severe by weight-for-height alone, 24 by MUAC alone, 142 by both. A concordance of 22.4%, and the whole of the disagreement is age — 31.4 months against 14.3.

PythonR150 minWHO Child Growth StandardsSphere StandardsUNICEF indicator definitions

The question the register can answer

Both admission criteria are in the case definitions and both are used in the field. Whether they find the same children is an empirical question, and it needs a register with both measurements on the same child.

The CMAM admission register has exactly that: MUAC and weight-for-height at admission, for 1,100 episodes. This lesson is what it says.

Compute both on the same children

import pandas as pd

cmam = pd.read_csv("cmam-admissions-2024.v1.csv")
cmam["whz"] = cmam.apply(whz, axis=1)          # from lesson 2

both = cmam[cmam["whz"].notna()].copy()
print(f"{len(both)} of {len(cmam)} admissions have both measurements")

both["sam_whz"] = both["whz"] < -3
both["sam_muac"] = both["muac_admission_mm"] < 115
both <- cmam |> filter(!is.na(whz))

both <- both |>
  mutate(sam_whz = whz < -3,
         sam_muac = muac_admission_mm < 115)

1,028 of 1,100. The 72 without a height are the missing-height defect from the dataset’s known issues, and they are the first finding: the two criteria do not have the same denominator even on the same register, because one needs two measurements and the other needs one.

The cross-tabulation

table = pd.crosstab(both["sam_muac"], both["sam_whz"],
                    rownames=["SAM by MUAC"], colnames=["SAM by WHZ"])
print(table)
both |> count(sam_muac, sam_whz)
Not severe by WHZ Severe by WHZ
Not severe by MUAC 394 468
Severe by MUAC 24 142

Read the two bold cells. 468 children are severe by weight-for-height and not by MUAC. 24 are severe by MUAC and not by weight-for-height. 142 are severe by both.

overlap = table.loc[True, True]
union = table.values.sum() - table.loc[False, False]
print(f"concordance {overlap / union:.1%} of {union} severe by either measure")
both |>
  summarise(overlap = sum(sam_muac & sam_whz),
            union = sum(sam_muac | sam_whz)) |>
  mutate(concordance = overlap / union)

22.4%. Of the children this register would call severe by one measure or the other, fewer than a quarter are called severe by both.

That number is not an artefact of this dataset. Published comparisons find overlaps in the 10% to 40% range depending on the population, and a programme that has not measured its own is assuming one.

The disagreement is age

mean_age = pd.Series({
    "MUAC only": both.loc[both["sam_muac"] & ~both["sam_whz"], "age_months"].mean(),
    "WHZ only": both.loc[both["sam_whz"] & ~both["sam_muac"], "age_months"].mean(),
    "Both": both.loc[both["sam_muac"] & both["sam_whz"], "age_months"].mean(),
})
print(mean_age.round(1))
both |>
  mutate(group = case_when(sam_muac & sam_whz ~ "both",
                           sam_muac ~ "muac only",
                           sam_whz ~ "whz only",
                           TRUE ~ "neither")) |>
  summarise(mean_age = mean(age_months), n = n(), .by = group)
Group Mean age
Severe by MUAC only 14.3 months
Severe by both 15.6 months
Severe by weight-for-height only 31.4 months

There it is. The children MUAC finds and weight-for-height misses are half the age of the children weight-for-height finds and MUAC misses.

The mechanism is simple and it is not a defect of either measure. MUAC grows with age: a healthy arm is about 135 mm at six months and about 155 mm at five years. A fixed 115 mm cut-off is therefore a much deeper deficit for a five-year-old than for an infant, so MUAC becomes progressively harder to fail as a child grows. Weight-for-height has no age term at all and applies equally across the range.

by_age = both.assign(
    band=pd.cut(both["age_months"], [5, 12, 24, 36, 60],
                labels=["6-11", "12-23", "24-35", "36-59"])
).groupby("band")[["sam_muac", "sam_whz"]].mean()
print((by_age * 100).round(1))
both |>
  mutate(band = cut(age_months, c(5, 12, 24, 36, 60),
                    labels = c("6-11", "12-23", "24-35", "36-59"))) |>
  summarise(across(c(sam_muac, sam_whz), mean), .by = band)

Run that and the two lines cross. MUAC identifies more of the youngest children; weight-for-height identifies more of the oldest. A programme admitting on MUAC alone is running a younger caseload than one admitting on weight-for-height alone, and that is a clinical fact about who gets treated, not a measurement detail.

Which one is right?

Neither, and the question is the wrong one. What each is for differs.

  • MUAC predicts mortality at least as well, and better in several studies. If the purpose of admission is to treat the children most likely to die, that is a strong argument.
  • Weight-for-height is the survey standard, and the IPC thresholds and international comparisons are built on it. If the purpose is to classify a population, that is decisive.
  • MUAC is operationally feasible at community level. Weight-for-height is not.

The sector’s answer is to use both, admit on either, and discharge on the one the child was admitted on. Which is sensible clinically and creates the analytical problem this lesson exists for.

What it means for your numbers

Four consequences, and each is a thing you will be asked about.

Caseload depends on the criterion. Admitting on either criterion gives a caseload of 634 severe children here; on MUAC alone, 166; on weight-for-height alone, 610. Those are not estimates of the same quantity.

Prevalence is not comparable across measures. A GAM by MUAC and a GAM by weight-for-height are different indicators. Lesson 6 shows what that does when a figure is read against the 15% threshold.

Discharge must use the admission criterion. A child admitted on MUAC and discharged on weight-for-height may be discharged before recovering, or held long after. The CMAM protocol is explicit and registers routinely are not.

A programme changing criterion breaks its own series. A caseload that rises 40% when the protocol changes is a definitional break, and the indicator design course’s rule about versioning a definition applies exactly.

for name, mask in [("either", both["sam_muac"] | both["sam_whz"]),
                   ("muac only", both["sam_muac"]),
                   ("whz only", both["sam_whz"])]:
    print(f"{name:10} caseload {mask.sum():>4}")
both |> summarise(either = sum(sam_muac | sam_whz),
                  muac = sum(sam_muac), whz = sum(sam_whz))

Report the pair, always

Severe acute malnutrition, admissions 2024, n = 1,028 with both measurements

  By MUAC (<115 mm)                166
  By weight-for-height (z < -3)    610
  By either                        634
  By both                          142    (22.4% of those severe by either)

  Children severe by MUAC alone average 14.3 months; by weight-for-height alone,
  31.4 months. The two criteria identify overlapping but substantially different
  caseloads, and the difference is age.

Six lines. They pre-empt the question, they name the mechanism, and they stop somebody comparing a MUAC-based caseload to a weight-for-height-based one as though the gap were a change in nutrition.

What comes next

You can classify children and you know what the classification depends on. The next unit turns to whether the survey that produced the measurements can be believed at all — the SMART plausibility report, which is where the standard deviation of 1.22 from lesson 2 finally gets read.

Teach this lesson

The lesson as a slide deck, with the prose kept in the speaker notes rather than on the slide. Generated from this page, so it cannot fall out of step with it.

Start the slideshowRead the slides

The PDF needs no software and projects from any machine. The PowerPoint file is there to be edited — add your organisation's branding, cut a section for a shorter session, or merge two lessons into a workshop.