cassionData Analysis

Back to the lessonLesson 5 of 8Counting people

Reach, coverage, and the people counted twelve times

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

    What this lesson covers

    • Three questions that sound like one
    • The cumulative sum that manufactures people
    • Deduplicating across months, when you can
    • Reach is not coverage, and the difference is the denominator
    • Cumulative counts in proposals
    • Which one belongs in your LogFrame
    • What comes next
    Speaker notes
    Three indicators that all sound like "how many people did we help", and the monthly series that turns 4,200 children into 50,000 the moment somebody sums the column.
  2. Slide 2 / 18

    Three questions that sound like one

    • Reach — how many distinct people received something, over a stated period.
    • Service volume — how many services were delivered. Larger than reach whenever anyone comes twice.
    • Coverage — what share of those who needed it got it. Requires a denominator and is the only one that says whether…
    Speaker notes
    "How many people did the programme help?" has three answers, and a proposal, a donor report and a coverage figure each need a different one. The names are used interchangeably in practice, which is how a programme reports 50,000 children reached in a district with 4,200 of them.
  3. Slide 3 / 18

    The cumulative sum that manufactures people — In Python

    monthly = (
        muac.assign(month=muac["screening_date"].dt.strftime("%Y-%m"))
        .groupby("month")
        .agg(screenings=("child_id", "size"),
             distinct_children=("child_id", "nunique"))
    )
    monthly["cumulative_naive"] = monthly["screenings"].cumsum()
    
    print(monthly)
    print("sum of monthly counts:  ", monthly["screenings"].sum())
    print("distinct children, year:", muac["child_id"].nunique())
    Speaker notes
    Here is the mechanism, and it is the single most common way this sector overstates its work.
  4. Slide 4 / 18

    The cumulative sum that manufactures people — In R

    monthly <- muac |>
      mutate(month = format(screening_date, "%Y-%m")) |>
      summarise(screenings = n(), distinct_children = n_distinct(child_id), .by = month) |>
      arrange(month) |>
      mutate(cumulative_naive = cumsum(screenings))
    
    c(sum_of_months = sum(monthly$screenings),
      distinct_year = n_distinct(muac$child_id))
  5. Slide 5 / 18

    The cumulative sum that manufactures people

    CorrectWrong
    Monthly reach, Januarydistinct people in January—
    Annual reachdistinct people across the yearsum of twelve monthly counts
    Cumulative reach to datedistinct people since programme startrunning total of monthly counts
    Speaker notes
    On this register the two happen to be close, because it is a one-round campaign and few children were screened twice. That is the exception. In a monthly programme — outpatient therapeutic care, a cash transfer, a health facility — a beneficiary appears in every month they receive something, and twelve monthly counts summed is twelve times a stable caseload. The arithmetic that goes wrong:
  6. Slide 6 / 18

    The cumulative sum that manufactures people

    • A cumulative reach figure can only be computed from person-level data — If your reporting is monthly aggregates, you…
    Speaker notes
    A cumulative reach figure can only be computed from person-level data. If your reporting is monthly aggregates, you cannot deduplicate across months, and the honest annual figure is not available — you must either say so or report the maximum month rather than the sum.
  7. Slide 7 / 18

    The cumulative sum that manufactures people — In Python

    annual_reach = muac["child_id"].nunique()
    service_volume = len(muac)
    print(f"reach {annual_reach:,} children; {service_volume:,} screening events")
  8. Slide 8 / 18

    The cumulative sum that manufactures people — In R

    c(reach = n_distinct(muac$child_id), volume = nrow(muac))
  9. Slide 9 / 18

    Deduplicating across months, when you can — In Python

    first_contact = (
        muac.sort_values("screening_date")
        .drop_duplicates(subset=["child_id"], keep="first")
        .assign(month=lambda d: d["screening_date"].dt.strftime("%Y-%m"))
    )
    new_by_month = first_contact.groupby("month").size()
    print(new_by_month.cumsum())
  10. Slide 10 / 18

    Deduplicating across months, when you can — In R

    first_contact <- muac |>
      arrange(screening_date) |>
      distinct(child_id, .keep_all = TRUE) |>
      mutate(month = format(screening_date, "%Y-%m"))
    
    first_contact |> count(month) |> arrange(month) |> mutate(cumulative = cumsum(n))
    Speaker notes
    Counting each person in the month of their first contact gives a cumulative series that rises to the true reach and never exceeds it. It also produces a genuinely useful management number — new beneficiaries per month, which distinguishes a programme that is growing from one that is serving the same people repeatedly. Report both, always: new this month and total served this month. They answer different questions and either alone is misleading.
  11. Slide 11 / 18

    Reach is not coverage, and the difference is the denominator — In Python

    reached = muac["child_id"].nunique()
    under5_population = 21500      # from the administrative frame, projected
    
    print(f"screening coverage: {reached / under5_population:.1%}")
    Speaker notes
    Reach counts who you served. Coverage says what fraction of those who needed the service got it, and it is the only one of the three that can say a programme is insufficient.
  12. Slide 12 / 18

    Reach is not coverage, and the difference is the denominator — In R

    c(coverage = n_distinct(muac$child_id) / 21500)
  13. Slide 13 / 18

    Reach is not coverage, and the difference is the denominator

    • Admissions over expected caseload is not coverage — Dividing the children admitted to treatment by the caseload you…
    • A reach figure with a population denominator is not coverage either — unless the population is the population in need
    Speaker notes
    Two failures to avoid, and both are common enough to have names. Admissions over expected caseload is not coverage. Dividing the children admitted to treatment by the caseload you expected tells you how good your expectation was, not what share of malnourished children you reached. Real coverage needs the number of malnourished children, which needs a survey — which is why coverage surveys exist as a separate methodology. A reach figure with a population denominator is not coverage either unless the population is the population in need. Screening 4,200 of 21,500 under-fives is screening coverage. It says nothing about what share of the malnourished children were found.
  14. Slide 14 / 18

    Cumulative counts in proposals

    • State the deduplication level. "Unique individuals, deduplicated within year, not across years" is a defensible and…
    • Never sum reach across sectors. A household receiving water, food and a protection service is one household, and…
    • Say when you cannot. "Aggregate figures are not deduplicated across partners; the true unique reach is lower" is a…
    Speaker notes
    Multi-year proposals ask for "people reached over the life of the project", and this is where the double-counting becomes a compliance issue rather than a methods one. Three rules that keep it honest:
  15. Slide 15 / 18

    Which one belongs in your LogFrame

    If the row is aboutUse
    Programme effort and costService volume
    People servedReach, with the deduplication level stated
    Whether the response is sufficientCoverage, with a needs-based denominator
    Whether people who start finishA completion or dropout rate
  16. Slide 16 / 18

    Which one belongs in your LogFrame

    Reach tells you what you did. Coverage tells you whether it was enough. A report with only the first is a description of activity, and every reader knows it.
    Speaker notes
    The last row is the one most often missing, and it is frequently the most informative — the Theory of Change lesson made that case with the 13.8% penta1 to penta3 dropout, which no reach or coverage figure would have revealed.
  17. Slide 17 / 18

    What comes next

    • Almost every indicator in this lesson already has an official definition published by somebody — UNICEF, WHO, the cluster, the SDG framework.
    Speaker notes
    Almost every indicator in this lesson already has an official definition published by somebody — UNICEF, WHO, the cluster, the SDG framework. The next lesson is about finding it, adopting it, and saying precisely where yours departs from it.
  18. Slide 18 / 18

    Where this goes next

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