Lab · Beginner
Three districts, six spellings
A WASH survey where one enumerator team wrote a district name four ways, splitting the worst-performing district into fragments. Normalise it with forcats, put every household on the JMP ladders, and wrap the whole thing in a function that runs on the next round.
Group this survey by district and you get six districts. There are three. One enumerator team wrote Nord-Ouest four different ways, and because the variants sort apart, the district with the worst water access is split into pieces small enough that none of them reaches the top of the table.
Nobody will tell you this happened. The table will look fine.
This lab runs locally in RStudio rather than in a hosted notebook. Colab can run R, but the runtime has to be switched by hand — and the course spent lesson 1 on a project that reopens a year later, which is not a thing a hosted session teaches you.
The file
wash-household-survey-2024.v1.csv — 2,403 household interviews across three
districts and eighteen communities, covering water source, collection time,
quantity, point-of-collection testing, sanitation and hygiene. Synthetic.
Set up first
An RStudio project with renv initialised, as lesson 1 describes, and the data
in its own folder. No setwd(), no absolute path. You will run this twice — once
now and once at the end, from a clean session — and the second run is the one
that proves it.
The task
Place every household on the three JMP service ladders — drinking water, sanitation, hygiene — and report coverage by district.
Five things stand in the way.
The district names. Normalise before you group, with fct_collapse() or a
recode, not with a chain of ifelse(). Then check: fct_count() should show
three levels and no NA. If the fourth variant reappears next round spelled a
fifth way, your code should fail visibly rather than quietly adding a district.
The ladder is not the source. An improved source more than 30 minutes round
trip is limited service, not basic. Roughly a quarter of these households sit
on limited service for that reason alone, and a classification built on
water_source alone misses every one of them. Use case_when(), and put the
30-minute test before the source test so the ordering is explicit.
Shared is not basic either. An improved sanitation facility shared between
households is limited service. shared_sanitation is the column; forgetting it
inflates basic sanitation.
Two denominators, not one. Water quality was tested on roughly a third of households. Access indicators use the whole sample; quality indicators use the tested subsample. Report each against its own denominator and say which is which in the column name — this is the habit the course keeps returning to.
Units that lie. Eleven records hold collection time in hours rather than
minutes, and fourteen hold litres for the whole household rather than per person.
Both look plausible alone. Find them against household_size and the
distribution, decide what to do, and record the decision.
What to hand in
An R script, sourced from a clean session, producing:
- a coverage table by district and ladder, with
districtas an ordered factor running worst to best rather than alphabetically - the share of households below the Sphere minimum of 15 litres per person per day
- the water-quality table, on its own denominator, with the tested share stated
- a cleaning log: every row you dropped or corrected, and why
Then wrap the cleaning in a single function taking the file path and returning the cleaned tibble, so the next round is one call.
Check your numbers
The dataset notes state what a correct analysis finds:
| Expected | |
|---|---|
| Below Sphere 15 L/person/day | about 13% |
| Round trip over 30 minutes | about 39% |
| Open defecation | about 13% |
| Basic hygiene service | about 34% |
If you get six districts, the normalisation did not run before the grouping. If
basic sanitation looks high, you have not applied shared_sanitation.
The questions to answer in prose
Three sentences each.
1. Normalising the district names moves one district’s ranking. Which one, in which direction, and what would have been decided differently if the table had gone out unnormalised?
2. About 530 households report treating their water but have no chlorine measurement. Dropping them is tempting and wrong. Say what those households have in common and what dropping them would do to the treated-water figure.
3. You reported water quality on a smaller denominator than access. A reviewer asks why the two coverage figures cannot be compared directly. Answer them.
How to know you are done
renv::restore() on another machine, one source(), and the same tables. Your
cleaning function should run unchanged if the next round adds a fourth district —
and should tell you it did, rather than silently producing a fourth row.
What this lab is not
It is not the JMP methodology. The ladder definitions are given to you here; how
they were arrived at and what they leave out belongs with the WASH content
itself. This lab is about the R: factors that hold their order, case_when()
that reads in the order it evaluates, and cleaning that survives being run by
someone else.