cassionAnalyse de données

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à.

PythonR105 minDéfinitions d'indicateurs de l'UNICEFNorme humanitaire fondamentale (CHS)

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.

Animer cette leçon

La leçon en diaporama, la prose étant reléguée dans les notes du présentateur plutôt que projetée. Produit à partir de cette page, dont il ne peut donc pas s'écarter.

Lancer le diaporamaLire les diapositives

Le PDF ne requiert aucun logiciel et se projette depuis n'importe quel poste. Le fichier PowerPoint est fait pour être modifié : appliquez la charte de votre organisation, retirez une section pour une séance plus courte, ou fusionnez deux leçons en atelier.