Leçon 4 sur 8
Unité · Inscrit n'est pas présent
Une grève qui ressemble à une urgence
SCH07 est à 88,2 % de présence et SCH18 à 85,2 %. Construisez le registre comme un calendrier complet et comptez chaque jour manquant comme une absence, et ils affichent 66,1 % et 63,9 % — les pires écoles du district, sur quinze jours où personne n'était censé être là.
Les lignes qui n’y sont pas
Les lignes de présence n’existent que pour les jours où une école était ouverte. Une date sans ligne est une fermeture, non une absence, et rien dans le fichier ne dit laquelle.
import pandas as pd
attendance = pd.read_csv("school-attendance-2024.v1.csv")
roster = pd.read_csv("school-roster-2024.v1.csv")
joined = attendance.merge(roster[["student_id", "school_id"]], on="student_id")
calendar = sorted(attendance["attendance_date"].unique())
days_per_school = joined.groupby("school_id")["attendance_date"].nunique()
print(f"school days in the calendar: {len(calendar)}")
print(days_per_school.sort_values().head())
library(dplyr)
attendance |>
left_join(roster, by = "student_id") |>
summarise(days = n_distinct(attendance_date), .by = school_id) |>
arrange(days)
Vingt-deux écoles ont les soixante jours. SCH07 et SCH18 en ont quarante-cinq.
missing = {
school: sorted(set(calendar) - set(group["attendance_date"]))
for school, group in joined.groupby("school_id")
}
for school, dates in missing.items():
if dates:
print(f"{school}: {len(dates)} days, {dates[0]} to {dates[-1]}")
# Which dates, not just how many. The pattern is the diagnosis.
Aux deux il manque exactement du 11 au 29 mars, et les mêmes quinze jours. Ce ne sont pas deux écoles avec un problème d’assiduité ; c’est un seul événement.
Des jours manquants consécutifs dans plusieurs écoles sont une fermeture jusqu’à preuve du contraire. Des jours manquants épars dans une seule école sont un problème d’enregistrement. La forme dit laquelle, et la regarder prend une ligne.
Ce qui arrive si on ne regarde pas
La façon naturelle de bâtir un tableau de présence est de construire la grille complète élèves × jours d’école et d’y reporter les pointages. C’est aussi la façon de transformer une grève en crise.
def attendance_rate(school, missing_counts_as_absent):
students = roster.loc[roster["school_id"] == school, "student_id"]
marks = attendance[attendance["student_id"].isin(students)]
present = marks["present"].isin(["true", "Y"]).sum()
if missing_counts_as_absent:
denominator = len(students) * len(calendar)
else:
denominator = marks["present"].isin(["true", "Y", "false", "N"]).sum()
return present / denominator
for school in ("SCH07", "SCH18", "SCH01"):
observed = attendance_rate(school, False)
filled = attendance_rate(school, True)
print(f"{school}: observed {observed:.1%}, grid-filled {filled:.1%}")
# Two denominators: marks made, and student-days in the calendar.
| École | Sur les pointages faits | Sur une grille complète |
|---|---|---|
| SCH07 | 88,2 % | 66,1 % |
| SCH18 | 85,2 % | 63,9 % |
| SCH01 | 91,3 % | 91,3 % |
Vingt-deux points, inventés. Sur les chiffres de la grille complète, SCH07 et SCH18 sont de loin les deux pires écoles du district, et un programme lisant ce tableau enverrait une réponse d’urgence contre l’abandon à deux écoles dont les enfants sont venus normalement chaque jour où on le leur a demandé.
L’école non touchée est inchangée, ce qui rend l’erreur si difficile à attraper : le tableau a l’air correct, l’essentiel l’est, et les deux lignes fausses sont les deux sur lesquelles on agit.
La règle
Construisez le dénominateur à partir des jours d’ouverture de l’école, non du calendrier.
open_days = joined.groupby("school_id")["attendance_date"].nunique()
enrolled = roster.groupby("school_id")["student_id"].nunique()
expected = (open_days * enrolled).rename("student_days_expected")
actual = joined.groupby("school_id").size().rename("marks_made")
coverage = (actual / expected).rename("mark_coverage")
print(pd.concat([expected, actual, coverage.round(3)], axis=1).head())
# Expected student-days uses each school's own open days.
Cela donne un second nombre utile : la couverture de pointage, la part des jours-élèves attendus qui portent effectivement un pointage. Une école à 100 % de présence et 60 % de couverture de pointage n’est pas une école à bonne assiduité.
Quand une fermeture est le constat
Quinze jours d’école font un quart du trimestre. La fermeture pèse plus que tout chiffre de présence de ce fichier, et une analyse qui exclut correctement ces jours puis n’en dit rien a retiré la plus grande chose qui se soit produite.
Attendance, February to April 2024
Average daily attendance, all schools 88.4% on marks made
SCH07 88.2%
SCH18 85.2%
SCH07 and SCH18 were closed for the fifteen school days from 11 to 29
March, a quarter of the term. Their attendance figures are computed on the
45 days they were open and are comparable with other schools; their
instructional time is not.
Counting the closure days as absences would report these two schools at
66.1% and 63.9% and rank them worst in the district.
Rapportez la fermeture en jours d’enseignement perdus, séparément de la présence. Les deux répondent à des questions différentes : la présence porte sur la venue des enfants, les jours d’enseignement sur le fait que l’école a eu lieu.
La forme générale
C’est la troisième fois que cette plateforme rencontre le même défaut dans un fichier différent.
| Cours | La chose absente | Ce à quoi cela ressemblait |
|---|---|---|
| Données de routine et DHIS2 | Une formation qui n’a pas rapporté | Un district à couverture en baisse |
| Analyse EAH | Une tournée que personne n’a conduite | Un district à fonctionnalité en hausse |
| Éducation | Un jour où l’école était fermée | Deux écoles en urgence d’abandon |
Dans les trois cas, l’absence n’est pas une valeur et rien dans le fichier ne l’annonce. L’habitude qui attrape les trois est la même : avant de calculer un taux, construisez ce que le dénominateur devrait être à partir d’autre chose que des lignes dont vous disposez, et comparez.
La suite
La présence décrit un trimestre. Savoir si un enfant est encore scolarisé l’année suivante est une autre question, et l’unité suivante suit la cohorte 2023 à travers passage, redoublement et abandon pour y répondre.