Back to the lesson·Lesson 1 of 8·What not to collect
The columns that are not there
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.
What this lesson covers
- Start with the schema, not the data
- The principle, stated as a rule about columns
- What the coarsening costs, measured
- The one that is genuinely a loss
- The 62 blank age bands
- What to write in the methodology note
- What comes next
Speaker notes
This dataset has fourteen columns and no name, no contact detail, no free text, no incident date, no location below district and no perpetrator detail. Every one of those absences is a decision, and every one of them can be justified by what the analysis needs.Start with the schema, not the data — In Python
import pandas as pd referrals = pd.read_csv("protection-referrals-2024.v1.csv") print(referrals.columns.tolist()) print(f"{len(referrals):,} cases, {len(referrals.columns)} columns")Start with the schema, not the data
Not here Why not Name, contact details Never leaves the case management system, under any circumstance Free-text narrative Identifying by construction, and no analysis reads it Incident date With an area and a category, frequently identifying Location below admin2 A village plus a category is a person Exact age Age band answers every disaggregation question age can Incident type, perpetrator relationship Not shared outside the case management agency at all Speaker notes
Fourteen columns for 1,850 protection cases. Now list what a case management system holds and this extract does not:Start with the schema, not the data
- Each row of that table is a decision someone made, and each one can be defended by naming the analysis it does not…
Speaker notes
Each row of that table is a decision someone made, and each one can be defended by naming the analysis it does not prevent. That is the test: not "is this sensitive" but "what would I be unable to compute without it".The principle, stated as a rule about columns
- Collect the minimum necessary. If no indicator needs a field, holding it is pure risk.
- Share less than you hold. The analysis extract is not the case file. Each step outward drops fields.
- Never share incident-level data outside the case management agency. Aggregate or do not send.
- Consent governs use. A person consenting to a referral has not consented to a research dataset.
- Safety first, always. Where an analysis and a survivor's safety conflict, the analysis loses.
Speaker notes
The GBV information management principles are usually taught as ethics. They are also, operationally, instructions about a schema:The principle, stated as a rule about columns — In Python
minimum = { "who": ["age_band", "sex", "disability_reported"], "where": ["admin1", "admin2"], "when": ["referral_month"], "what": ["case_category", "service_requested"], "pathway": ["consent_to_refer", "referral_made", "referral_accepted", "days_to_first_service", "case_status"], } print({k: len(v) for k, v in minimum.items()})The principle, stated as a rule about columns — In R
# Five groups of fields, each earning its place by an indicator that needs it.The principle, stated as a rule about columns
- Every field in this extract maps to an indicator —
days_to_first_serviceexists because the 72-hour clinical standard…
Speaker notes
Every field in this extract maps to an indicator.days_to_first_serviceexists because the 72-hour clinical standard for GBV health care needs it;disability_reportedexists because the equity gap is the finding this dataset was built to surface. A field with no indicator behind it should not be in the extract.- Every field in this extract maps to an indicator —
What the coarsening costs, measured — In Python
print(referrals["age_band"].value_counts(dropna=False)) print(referrals["referral_month"].nunique(), "distinct periods") print(referrals["admin2"].nunique(), "areas")Speaker notes
The claim that coarsening is cheap should be tested rather than asserted.What the coarsening costs, measured — In R
referrals |> count(age_band) referrals |> summarise(periods = n_distinct(referral_month), areas = n_distinct(admin2))What the coarsening costs, measured
- Timeliness: measured in days from referral to service, which is already a duration and does not need a calendar…
- Seasonality: monthly is the finest resolution any protection trend is read at, and a weekly series on 1,850 cases…
- Age disaggregation: the bands are the reporting categories. A child, an adolescent, a working-age adult and an…
- So the coarsening costs nothing that anyone asked for — That is what makes it defensible, and it is why the argument…
Speaker notes
Five age bands, twelve months, six areas. Now ask what an exact age and an exact date would add: So the coarsening costs nothing that anyone asked for. That is what makes it defensible, and it is why the argument for it is analytical rather than merely cautious.The one that is genuinely a loss
- Dropping incident type means you cannot say which forms of violence the referral pathway serves worst — That is a real…
Speaker notes
Not every omission is free, and pretending otherwise is how a data protection argument loses credibility. Dropping incident type means you cannot say which forms of violence the referral pathway serves worst. That is a real analytical loss, and the answer is not that it does not matter. The answer is that the analysis belongs inside the case management agency, run by the people who hold the data, and what leaves is the conclusion rather than the file.The one that is genuinely a loss — In Python
print("Question: does the pathway serve some incident types worse than others?") print("Where it can be answered: inside the case management agency") print("What leaves the agency: the finding, not the disaggregation")The one that is genuinely a loss — In R
# The right answer to "we need incident type" is often "we will run it and # send you the result", not "no".The one that is genuinely a loss
- "You cannot have the file, and here is the answer to your question" is the professional response — and it is available…
Speaker notes
"You cannot have the file, and here is the answer to your question" is the professional response, and it is available far more often than either a flat refusal or a quiet handover.The 62 blank age bands — In Python
missing = referrals["age_band"].isna() print(f"{missing.sum()} cases with no age band ({missing.mean():.1%})") print(referrals.loc[missing, "case_category"].value_counts())The 62 blank age bands — In R
referrals |> filter(is.na(age_band)) |> count(case_category)Speaker notes
Age band is both the most-used disaggregation and the field most often missing in real intake data, because it is asked at a moment when asking is intrusive. Sixty-two cases is 3.4% and it is not distributed evenly, so an age- disaggregated table has a smaller denominator than the pathway table beside it and must say so. The instinct to impute is wrong here for a reason specific to this sector: an imputed age band attached to a real case in a protection dataset is a fabricated attribute of an identifiable person.What to write in the methodology note — Example
Data handling Analysis extract holds 14 fields for 1,850 cases. It contains no name, contact detail, free text, incident date, location below admin2, exact age, incident type or perpetrator detail. Age is recorded in five bands and time in months. Both are sufficient for every indicator reported here, and both reduce the risk that a row can be matched to a person. Incident-level fields remain in the case management system. Analyses requiring them are run by the case management agency and reported as findings rather than shared as data. 62 cases (3.4%) have no age band. Age-disaggregated figures are computed on 1,788 cases and are labelled accordingly.What to write in the methodology note
- Write this before the results, not in an annex — A protection report whose data handling section is at the back has…
Speaker notes
Write this before the results, not in an annex. A protection report whose data handling section is at the back has invited every reader to skip the one part that governs what the rest of it is allowed to say.What comes next
- Removing columns reduces risk and does not eliminate it.
Speaker notes
Removing columns reduces risk and does not eliminate it. The next lesson is what happens when you cross-tabulate the columns that are left, and the point at which a perfectly anonymous dataset produces a table that identifies someone.