cassionData Analysis

Lesson 1 of 8

Unit · Enrolment and its denominator

109% enrolled, 97% enrolled

Two ratios from one register. The gross is 109.2% and the net is 97.4%, both are correct, and the twelve points between them are children who are in school at the wrong age rather than children who are missing.

PythonR105 minSustainable Development Goals (SDG)UNICEF indicator definitions

Two ratios, one register

import pandas as pd

enrolment = pd.read_csv("school-enrolment-2024.v1.csv")
population = pd.read_csv("school-age-population-2024.v1.csv")

current = enrolment[enrolment["school_year"] == 2024]
primary = current[current["grade"].between(1, 6)]

denominator = population.loc[
    (population["reference_year"] == 2024)
    & population["age_years"].between(6, 11),
    "projected_population",
].sum()

gross = len(primary) / denominator
net = len(primary[primary["age_years"].between(6, 11)]) / denominator

print(f"gross enrolment ratio: {gross:.1%}")
print(f"net enrolment ratio:   {net:.1%}")
library(dplyr)

primary <- enrolment |> filter(school_year == 2024, between(grade, 1, 6))
denominator <- population |>
  filter(reference_year == 2024, between(age_years, 6, 11)) |>
  summarise(n = sum(projected_population)) |> pull(n)

tibble(
  gross = nrow(primary) / denominator,
  net = sum(between(primary$age_years, 6, 11)) / denominator
)
Ratio Numerator Denominator Value
Gross All primary enrolees, any age Children aged 6–11 109.2%
Net Primary enrolees aged 6–11 Children aged 6–11 97.4%

The numerators differ; the denominator is identical. That is the whole definition, and it is why the two ratios are not two estimates of one thing.

Why a ratio can exceed 100%

A gross ratio above 100% is not an error. Three things produce it and only one is a defect.

Over-age and under-age enrolment. Children outside the official age range are in the numerator and not in the denominator. This is the dominant cause here and it is a real feature of the system, not a data problem.

A denominator that is too small. The population file is a projection, not a count, and a projection that undershoots inflates every ratio built on it.

Double counting. A child enrolled at two schools appears twice. This one is a defect, and this register has it.

duplicates = current.duplicated(subset=["student_id", "school_year"], keep=False)
print(f"student-years appearing more than once: {duplicates.sum()}")

unique = current.drop_duplicates(subset=["student_id", "school_year"])
unique_primary = unique[unique["grade"].between(1, 6)]
print(f"gross ratio after deduplication: {len(unique_primary) / denominator:.1%}")
enrolment |> filter(school_year == 2024) |>
  count(student_id) |> filter(n > 1) |> nrow()

Twelve students appear twice, once under each school, because a transfer was recorded as a new enrolment rather than a move. Deduplicate on student and year before either ratio, and note that the effect here is small — the point is not the size, it is that a register which double-counts is wrong about who exists.

The denominator is a projection

CENSUS_YEAR, GROWTH = 2015, 0.021
factor = (1 + GROWTH) ** (2024 - CENSUS_YEAR)
print(f"nine years compounded at {GROWTH:.1%}: factor {factor:.3f}")
print(f"so about {1 - 1 / factor:.0%} of the denominator is an assumption")
(1 + 0.021)^(2024 - 2015)

A factor of 1.21, so roughly a sixth of the denominator was never counted. This is the immunisation denominator from the public health course, in a different sector: a census base, a growth assumption, and nine years of compounding.

The consequence is specific. If the projection is 5% too low, the gross ratio falls from 109.2% to about 104% and the net from 97.4% to about 93%. Neither conclusion changes, but a report claiming primary enrolment rose two points between years may be reporting the growth rate rather than the schools.

for error in (-0.05, 0.0, 0.05):
    adjusted = denominator * (1 + error)
    print(f"projection {error:+.0%}: gross {len(primary) / adjusted:.1%}, "
          f"net {len(primary[primary['age_years'].between(6, 11)]) / adjusted:.1%}")
# Vary the denominator and see which conclusions survive.

Show the sensitivity rather than the point estimate where the denominator is projected. It costs three lines and it is the difference between a ratio and a ratio you can defend.

Which one to report

Neither, alone.

Net enrolment answers “are children of school age in school”. It is the SDG 4.1 framing and the right ratio for a coverage question. It cannot exceed 100%, which makes it the safer number to publish.

Gross enrolment answers “how much primary schooling is being delivered”. It is the right ratio for a capacity question — teachers, classrooms, textbooks — because an over-age child needs a desk exactly as much as an in-age one.

The gap between them is the finding, and it is the reason to report both: twelve points of over-age enrolment is a statement about repetition and late entry that neither ratio makes on its own.

Primary enrolment, 2024, four districts

  Gross enrolment ratio       109.2%   1,052 enrolees / 963 children aged 6-11
  Net enrolment ratio          97.4%     938 in-age enrolees / same denominator
  Over-age share of enrolment  36.4%   above the official age for their grade

  Denominator is a projection from the 2015 census at 2.1% a year. A 5%
  error in it moves the gross ratio by about five points and changes no
  conclusion.
  12 student-years were recorded twice after transfers and are deduplicated.

What the ratios cannot tell you

Neither is attendance. A child enrolled and never present is in both numerators. The next unit is that distinction, and it is worth more than either ratio.

Neither is completion. Enrolment is a stock at a point in the year; whether those children finish is a cohort question and the third unit.

Neither is learning. A system can enrol every child of school age and teach none of them, and the last unit is the instrument that would notice.

What comes next

Twelve points of the gap between the two ratios is over-age enrolment. The next lesson is who those children are, why being behind is the strongest predictor in this register, and how repetition makes it compound.

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.