cassionData Analysis

Back to the lessonLesson 1 of 8What 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.

Slides · PDFSlides · PowerPoint

  1. Slide 1 / 22

    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.
  2. Slide 2 / 22

    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")
  3. Slide 3 / 22

    Start with the schema, not the data — In R

    library(dplyr)
    
    referrals |> glimpse()
  4. Slide 4 / 22

    Start with the schema, not the data

    Not hereWhy not
    Name, contact detailsNever leaves the case management system, under any circumstance
    Free-text narrativeIdentifying by construction, and no analysis reads it
    Incident dateWith an area and a category, frequently identifying
    Location below admin2A village plus a category is a person
    Exact ageAge band answers every disaggregation question age can
    Incident type, perpetrator relationshipNot 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:
  5. Slide 5 / 22

    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".
  6. Slide 6 / 22

    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:
  7. Slide 7 / 22

    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()})
  8. Slide 8 / 22

    The principle, stated as a rule about columns — In R

    # Five groups of fields, each earning its place by an indicator that needs it.
  9. Slide 9 / 22

    The principle, stated as a rule about columns

    • Every field in this extract maps to an indicator — days_to_first_service exists because the 72-hour clinical standard…
    Speaker notes
    Every field in this extract maps to an indicator. days_to_first_service exists because the 72-hour clinical standard for GBV health care needs it; disability_reported exists 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.
  10. Slide 10 / 22

    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.
  11. Slide 11 / 22

    What the coarsening costs, measured — In R

    referrals |> count(age_band)
    referrals |> summarise(periods = n_distinct(referral_month),
                           areas = n_distinct(admin2))
  12. Slide 12 / 22

    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.
  13. Slide 13 / 22

    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.
  14. Slide 14 / 22

    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")
  15. Slide 15 / 22

    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".
  16. Slide 16 / 22

    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.
  17. Slide 17 / 22

    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())
  18. Slide 18 / 22

    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.
  19. Slide 19 / 22

    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.
  20. Slide 20 / 22

    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.
  21. Slide 21 / 22

    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.
  22. Slide 22 / 22

    Where this goes next

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