cassionAnalyse de données

Leçon 5 sur 8

Unité · La cohorte

Trois issues qui doivent sommer à un

70,4 % de passages, 9,8 % de redoublements, 10,2 % d'abandons, 5,7 % d'achèvements et 2,9 % de transferts. Chacune exige le même dénominateur, et les transferts sont la raison pour laquelle ce n'est pas l'effectif inscrit.

PythonR105 minObjectifs de développement durable (ODD)Définitions d'indicateurs de l'UNICEFEnquête par grappes à indicateurs multiples (MICS)

L’année, comme un ensemble de sorties

import pandas as pd

enrolment = pd.read_csv("school-enrolment-2024.v1.csv")
clean = enrolment[enrolment["age_years"] <= 20]
cohort = clean[clean["school_year"] == 2023]

outcomes = cohort["end_of_year_status"].value_counts(normalize=True)
print((outcomes * 100).round(1))
print(f"\ncohort: {len(cohort)} students")
library(dplyr)

enrolment |>
  filter(age_years <= 20, school_year == 2023) |>
  count(end_of_year_status) |>
  mutate(share = n / sum(n))
Issue Élèves Part
Passés 910 70,4 %
Abandonné 132 10,2 %
Redoublé 127 9,8 %
Achevé la dernière année 74 5,7 %
Transféré 37 2,9 %
Encore inscrits à la clôture 12 0,9 %

Les trois taux principaux sont le passage, le redoublement et l’abandon, et ils ne signifient quelque chose que s’ils partagent un dénominateur. Cela paraît évident et c’est l’étape la plus souvent sautée.

Le dénominateur n’est pas l’effectif inscrit

Deux catégories le compliquent, et dans des sens opposés.

Les transferts ne sont pas des abandons. Un enfant parti dans une autre école est toujours scolarisé. Les compter comme abandons surestime l’abandon de près de trois points et — pire — attribue une réussite du système à un échec d’école.

Les transferts ne sont pas non plus des réussites. Ils ne peuvent pas être comptés comme passages, car ce registre ne sait pas s’ils se sont réinscrits.

def rates(frame, exclude_transfers):
    base = frame[frame["end_of_year_status"] != "transferred-out"] \
        if exclude_transfers else frame
    return {
        "n": len(base),
        "promotion": (base["end_of_year_status"]
                      .isin(["promoted", "completed-final-grade"]).mean()),
        "repetition": base["end_of_year_status"].eq("repeated").mean(),
        "dropout": base["end_of_year_status"].eq("dropped-out").mean(),
    }

for exclude in (False, True):
    result = rates(cohort, exclude)
    label = "excluding transfers" if exclude else "all students"
    print(f"{label:20} n={result['n']}  "
          f"promotion {result['promotion']:.1%}  "
          f"repetition {result['repetition']:.1%}  "
          f"dropout {result['dropout']:.1%}")
cohort |>
  filter(end_of_year_status != "transferred-out") |>
  summarise(n = n(),
            promotion = mean(end_of_year_status %in% c("promoted", "completed-final-grade")),
            repetition = mean(end_of_year_status == "repeated"),
            dropout = mean(end_of_year_status == "dropped-out"))

C’est le dénominateur du taux de guérison PCIMA rencontré plus tôt dans ce module, dans un autre secteur. La convention y était d’exclure les transferts parce que le programme ne peut pas revendiquer leur issue ; la convention est ici la même, pour la même raison. Dites laquelle vous avez employée, et les trois taux sommeront à quelque chose de défendable.

Le redoublement est une décision, non un événement

by_district = clean.groupby("admin2")["repeating"].agg(["mean", "size"])
print((by_district * [100, 1]).round(1))
enrolment |> filter(age_years <= 20) |>
  summarise(repeating = mean(repeating), n = n(), .by = admin2)
District Taux de redoublement n
Sud 12,3 % 583
Artibonite 12,1 % 618
Nord-Ouest 12,0 % 625
Centre 7,4 % 624

Centre rapporte un redoublement inférieur de près de cinq points à tous les autres districts. C’est soit le district le plus performant de la région, soit une habitude d’enregistrement, et le registre seul ne peut pas trancher.

C’est une habitude d’enregistrement : Centre signale une partie de ses vrais redoublants comme nouveaux entrants. La façon de le soupçonner sans qu’on vous le dise est que le redoublement devrait suivre le retard d’âge, et à Centre il ne le suit pas — 8,7 % de redoublement contre 11,8 % ailleurs, alors que la part de retard d’âge de Centre vaut 40,6 % contre 35,7 %. Le district qui rapporte le moins de redoublement a le plus d’enfants en retard d’âge, ce qui est à l’envers pour toute explication autre que le codage.

centre = clean[(clean["admin2"] == "Centre") & (clean["school_year"] == 2023)]
elsewhere = clean[(clean["admin2"] != "Centre") & (clean["school_year"] == 2023)]
for name, frame in [("Centre", centre), ("elsewhere", elsewhere)]:
    over = frame["age_years"] > frame["grade"] + 5
    print(f"{name}: repetition {frame['repeating'].mean():.1%}, "
          f"over-age {over.mean():.1%}")
# Repetition should predict over-age. Where it does not, suspect the coding.

Un taux en décalage avec l’indicateur qu’il cause mécaniquement est une question sur le bureau avant d’être un constat sur les écoles. C’est le même raisonnement que le fourre-tout des motifs de clôture du cours de protection, et il mérite d’être un réflexe.

L’abandon par année, et le pic de sixième

by_grade = cohort[cohort["grade"].between(1, 6)].groupby("grade").agg(
    n=("student_id", "size"),
    dropout=("end_of_year_status", lambda s: s.eq("dropped-out").mean()),
    repetition=("end_of_year_status", lambda s: s.eq("repeated").mean()),
)
print((by_grade * [1, 100, 100]).round(1))
cohort |> filter(between(grade, 1, 6)) |>
  summarise(n = n(),
            dropout = mean(end_of_year_status == "dropped-out"),
            repetition = mean(end_of_year_status == "repeated"), .by = grade)
Année n Abandon Redoublement
1 149 8,1 % 2,0 %
2 271 8,5 % 7,0 %
3 332 13,0 % 6,6 %
4 231 8,7 % 10,4 %
5 165 8,5 % 19,4 %
6 110 18,2 % 12,7 %

Deux choses de ce tableau demandent une lecture attentive.

Le redoublement monte avec l’année et l’abandon non. La cinquième retient 19,4 % de ses élèves alors que son abandon vaut 8,5 % ; la sixième fait l’inverse. Les deux sont des sorties alternatives d’un même point de décision, et lire l’une seule donne une forme fausse du problème.

L’abandon en sixième vaut 18,2 % sur 110 élèves. C’est le taux le plus élevé du tableau et le plus petit dénominateur, donc avant d’en faire la priorité, posez-lui un intervalle — la machinerie du cours sur les enquêtes, sur une proportion qui bougerait de plusieurs points si quatre enfants avaient fait autre chose.

Rapportez les sorties, puis les taux

End of school year 2023, 1,292 students

  Promoted                     70.4%   910
  Dropped out                  10.2%   132
  Repeated                      9.8%   127
  Completed the final grade     5.7%    74
  Transferred out               2.9%    37   excluded from the rates below
  Still enrolled at cut-off     0.9%    12

  Rates on 1,255 students, transfers excluded:
    Promotion (incl. completion)  78.4%
    Repetition                    10.1%
    Dropout                       10.5%

  Centre reports repetition at 7.4% against 12.0-12.3% elsewhere while
  holding the highest over-age share of the four districts. Treat as a
  recording difference pending verification, not as performance.

La suite

Ce sont les sorties d’une année. Les transformer en « combien d’enfants achèvent le primaire » exige une cohorte, et la leçon suivante en construit une — avec la raison pour laquelle le nombre qu’elle produit est presque certainement faux.

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.