Série Sénégal — Socle de données intégré

Un univers éducatif sénégalais simulé, cohérent, alimentant tous les volets

R
simulation
data-engineering
education
Senegal
EMIS
multilevel
reproducibility

Pièce fondatrice du bac à sable « Sénégal » : un générateur unique qui simule un système éducatif sénégalais structurellement vraissemblable — 14 régions, inspections d’académie (IA), inspections de l’éducation et de la formation (IEF), écoles élémentaires, enseignants et centres préscolaires. Le socle produit une couche de variables latentes (« vérité ») et les liens causals qui la traversent (gouvernance, enclavement, ratio élèves-maître, présence enseignante, niveau des élèves), de sorte que chaque volet en aval consomme la même réalité et que les analyses soient mutuellement articulées. Sorties : un jeu de fichiers CSV canoniques et un contrat de données documenté. Code R entièrement paramétré et annoté pour réemploi.

Author

Francisco Martin-Gomez

Published

June 30, 2026

# ---------------------------------------------------------------------------
# SPINE for the "Sénégal" series. It builds ONE coherent synthetic universe.
# Design philosophy:
#   * The spine writes the STRUCTURE (geography, schools, teachers, preschool
#     centres) and a LATENT "truth" layer (governance, remoteness, school
#     quality, pupil-teacher ratio, teacher attendance propensity, pupil ability).
#   * Each downstream volet GENERATES ITS OWN OBSERVED DATA from these latents
#     (e.g. V3 simulates 3 noisy attendance waves; V4 simulates item responses
#     with injected DIF). Same latents everywhere => analyses stay articulated.
# Everything is parameterised in the `params` chunk; nothing is hard-coded later.
# ---------------------------------------------------------------------------

library(dplyr)
library(tidyr)
library(purrr)
library(tibble)
library(ggplot2)
library(readr)

set.seed(50)   # reproducibility for the whole series anchor
params <- list(
  # --- Scale (a deliberately scaled-down but structurally realistic universe) -
  n_ecoles      = 2500L,   # elementary schools simulated
  n_prescolaire = 3500L,   # preschool centres simulated (feeds V5)
  ief_total_hint = 55L,    # target number of IEF nationwide
  n_reform_ia   = 6L,      # IA piloting "strengthened deconcentration" (V1 treatment)

  # --- Pupil-teacher ratio (PTR) model: PTR_s on the log scale ---------------
  ptr_base      = 40,      # national target PTR
  b_remote_ptr  = 0.45,    # remoteness inflates PTR (under-staffing of remote areas)
  b_gov_ptr     = 0.10,    # better governance lowers PTR (more equitable allocation)
  b_reform_ptr  = 0.30,    # the deconcentration reform lowers PTR (the effect V1 estimates)
  sd_ptr        = 0.12,    # idiosyncratic noise (log scale)

  # --- Teacher attendance propensity (probability present), logit scale ------
  att_base_logit = 1.6,    # ~ plogis(1.6) ≈ 0.83 baseline presence
  b_remote_att  = 1.2,     # remoteness lowers presence
  b_gov_att     = 0.5,     # governance/supervision raises presence
  b_fonct_att   = 0.4,     # tenured (fonctionnaire) slightly more present
  sd_att        = 0.5,     # teacher-level noise

  # --- Pupil latent ability (school mean), standardized ----------------------
  b_quality_ab  = 0.50,    # school quality raises ability
  b_ptr_ab      = -0.25,   # higher PTR lowers ability (per SD of PTR)
  b_att_ab      = 0.35,    # teacher presence raises ability
  b_remote_ab   = -0.20,   # residual remoteness penalty
  sd_school_ab  = 0.30,    # residual school-level ability noise

  # --- Schooling coverage (denominator = simulated reference population 6-11) -
  part_filles_base = 0.48, # girls' share of enrolment (low-remoteness baseline)
  b_remote_filles  = 0.10, # remoteness lowers girls' share of enrolment
  ger_cible_base   = 0.95, # target gross enrolment ratio in low-remoteness areas
  b_remote_ger     = 0.40, # remoteness lowers the target GER (→ ~0.60 in enclaves)
  part_filles_pop  = 0.49, # girls' share of the school-age population (demographic)
  part_age_officiel = 0.80, # share of the enrolled who are of official age (for NER)

  # --- Governance → girls' access (equity signal consumed by V2) -------------
  b_gov_filles        = 0.020, # better IA governance raises girls' share of enrolment
  b_gov_remote_filles = 0.030, # ...more so where remoteness is high (narrows the gap)

  # --- IEF-level managerial latent (genuine IEF variance for the V2 multilevel)
  sigma_ief     = 1.0,     # SD of the IEF-level managerial effect
  b_ief_ab      = 0.30,    # its contribution to school-mean ability

  out_dir       = "files/projet_50"
)

dir.create(params$out_dir, recursive = TRUE, showWarnings = FALSE)

1 Objet et approche « univers intégré »

Ce notebook ne produit pas une analyse : il fabrique le terrain commun de toute la série. L’idée est qu’un seul générateur simule un système éducatif sénégalais cohérent, et que chaque volet y puise sa tranche. Les mêmes écoles, enseignants et élèves circulent ainsi d’un volet à l’autre, ce qui rend les analyses mutuellement articulées plutôt que juxtaposées.

Le socle écrit deux choses : la structure (géographie administrative, écoles, enseignants, centres préscolaires) et une couche de variables latentes — la « vérité » de l’univers (gouvernance, enclavement, qualité, ratio élèves-maître, présence, niveau des élèves). Les volets en aval génèrent ensuite leurs données observées à partir de ces latentes : c’est ce qui leur permet de « retrouver » des effets “vrais” déjà isolés dans la litétrature, tout en faisant chacun leur propre travail de données (nettoyage, appariement, mesure).

2 Ancrage sur la structure réelle du Sénégal

La simulation respecte l’architecture administrative effective : 14 régions ; au niveau déconcentré, les inspections d’académie (IA) au niveau régional — Dakar en comptant trois — qui polarisent des inspections de l’éducation et de la formation (IEF) au niveau départemental ; sous les IEF, les écoles élémentaires et les centres préscolaires (incluant les Cases des tout-petits, communautaires, à côté du public et du privé). Les noms, le nombre de niveaux et les ordres de grandeur sont réalistes ; les effectifs sont volontairement réduits pour un calcul rapide, sans altérer la structure.

3 Hiérarchie administrative : régions → IA → IEF

# poids = rough share of national enrolment; remoteness in [0,1] (0 = urban core).
regions <- tribble(
  ~region,         ~poids, ~remoteness,
  "Dakar",          0.22,   0.05,
  "Thiès",          0.13,   0.15,
  "Diourbel",       0.09,   0.30,
  "Saint-Louis",    0.07,   0.35,
  "Kaolack",        0.08,   0.30,
  "Louga",          0.06,   0.45,
  "Fatick",         0.06,   0.40,
  "Kaffrine",       0.05,   0.55,
  "Ziguinchor",     0.05,   0.55,
  "Kolda",          0.05,   0.70,
  "Tambacounda",    0.06,   0.75,
  "Matam",          0.04,   0.65,
  "Sédhiou",        0.03,   0.70,
  "Kédougou",       0.02,   0.90
) |>
  mutate(poids = poids / sum(poids))   # normalise to a proper distribution
ia <- regions |>
  mutate(n_ia = if_else(region == "Dakar", 3L, 1L)) |>
  uncount(n_ia, .id = "ia_seq") |>
  mutate(
    ia_name = if_else(region == "Dakar",
                      c("Dakar", "Pikine-Guédiawaye", "Rufisque")[ia_seq],
                      region),
    ia_id   = sprintf("IA%02d", row_number()),
    # Governance / management-quality index per IA: mild urban edge + noise.
    g_ia    = as.numeric(scale(-0.4 * remoteness + rnorm(n()))) ) |>
  select(ia_id, ia_name, region, poids, remoteness, g_ia)

# "Strengthened deconcentration" pilot: the treatment V1 will try to recover.
reform_ids <- sample(ia$ia_id, params$n_reform_ia)
ia <- ia |> mutate(reform = as.integer(ia_id %in% reform_ids))

ia |> select(ia_id, ia_name, region, g_ia, reform) |> head(16) |>
  knitr::kable(digits = 2, caption = "Inspections d'Académie (16).")
Inspections d’Académie (16).
ia_id ia_name region g_ia reform
IA01 Dakar Dakar 1.14 0
IA02 Pikine-Guédiawaye Dakar -0.68 1
IA03 Rufisque Dakar 0.46 0
IA04 Thiès Thiès 1.05 0
IA05 Diourbel Diourbel -1.96 0
IA06 Saint-Louis Saint-Louis -0.10 0
IA07 Kaolack Kaolack 0.76 0
IA08 Louga Louga -0.56 0
IA09 Fatick Fatick 1.51 1
IA10 Kaffrine Kaffrine -1.72 1
IA11 Ziguinchor Ziguinchor 0.54 1
IA12 Kolda Kolda 0.80 0
IA13 Tambacounda Tambacounda -0.60 1
IA14 Matam Matam 0.36 0
IA15 Sédhiou Sédhiou -0.51 1
IA16 Kédougou Kédougou -0.50 0
# Number of IEF per IA ~ proportional to regional weight (min 1).
ia_n <- ia |> count(region, name = "n_ia_region")
ief <- ia |>
  left_join(ia_n, by = "region") |>
  mutate(n_ief = pmax(1L, round(poids * params$ief_total_hint / n_ia_region))) |>
  uncount(n_ief, .id = "ief_seq") |>
  mutate(ief_id = sprintf("IEF%03d", row_number()),
         ief_effect = rnorm(n(), 0, params$sigma_ief)) |>   # genuine IEF-level variance
  select(ief_id, ia_id, ia_name, region, remoteness, g_ia, reform, ief_effect)

cat("Nombre d'IEF simulées :", nrow(ief), "\n")
Nombre d'IEF simulées : 55 

4 Écoles : effectifs, ratio élèves-maître, qualité

# Assign each school to a region (∝ poids), then to an IEF uniformly within region.
ief_by_region <- split(ief$ief_id, ief$region)
draw_ief <- function(reg) sample(ief_by_region[[reg]], 1)

set.seed(501)
ecoles <- tibble(
  ecole_id = sprintf("E%05d", seq_len(params$n_ecoles)),
  region   = sample(regions$region, params$n_ecoles, replace = TRUE, prob = regions$poids)
) |>
  mutate(ief_id = map_chr(region, draw_ief)) |>
  left_join(select(ief, ief_id, ia_id, remoteness, g_ia, reform, ief_effect), by = "ief_id") |>
  # school-level remoteness = regional remoteness + small idiosyncratic noise
  mutate(remoteness_s = pmin(pmax(remoteness + rnorm(n(), 0, 0.05), 0), 1),
         # milieu: urban probability falls with remoteness
         milieu = if_else(runif(n()) < (0.8 - 0.7 * remoteness_s), "urbain", "rural"),
         milieu = factor(milieu, levels = c("urbain", "rural")),
         # enrolment: lognormal, larger in urban schools
         mu_enrol = if_else(milieu == "urbain", 320, 180),
         enrol = pmax(round(rlnorm(n(), log(mu_enrol) - 0.35^2/2, 0.35)), 25L),
         # gender split: girls' share falls with remoteness but rises with good
         # governance — more so where remoteness is high (governance narrows the gap)
         part_filles = pmin(pmax(params$part_filles_base -
                        params$b_remote_filles * remoteness_s +
                        params$b_gov_filles * g_ia +
                        params$b_gov_remote_filles * g_ia * remoteness_s +
                        rnorm(n(), 0, 0.02), 0.30), 0.55),
         eleves_filles  = round(enrol * part_filles),
         eleves_garcons = enrol - eleves_filles)

# --- Latent pupil-teacher ratio (PTR) on the log scale ---------------------
# Remote, low-governance, non-reform schools are UNDER-staffed (high PTR).
ecoles <- ecoles |>
  mutate(
    log_ptr = log(params$ptr_base) +
              params$b_remote_ptr * remoteness_s -
              params$b_gov_ptr   * g_ia -
              params$b_reform_ptr * reform +
              rnorm(n(), 0, params$sd_ptr),
    ptr = exp(log_ptr),
    # teachers implied by enrolment and PTR (at least 1)
    n_teachers = pmax(1L, round(enrol / ptr)),
    # school quality latent (standardized): better with governance, worse remote
    quality = as.numeric(scale(
      params$b_quality_ab * g_ia - params$b_remote_ab * 0 - 0.6 * remoteness_s +
      rnorm(n(), 0, params$sd_school_ab))) )

summary(ecoles$ptr) |> round(1)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   22.5    36.2    42.3    43.5    49.9    83.3 

5 Enseignants : attributs et propension de présence

set.seed(502)
enseignants <- ecoles |>
  select(ecole_id, ief_id, ia_id, region, milieu, remoteness_s, g_ia, reform, n_teachers) |>
  uncount(n_teachers) |>
  mutate(
    enseignant_id = sprintf("T%06d", row_number()),
    # gender: teaching corps skews male, more so in rural areas
    genre = if_else(runif(n()) < if_else(milieu == "rural", 0.68, 0.55), "H", "F"),
    genre = factor(genre, levels = c("F", "H")),
    # status: contractuels over-represented in remote/under-resourced settings
    p_fonct = plogis(0.4 - 1.0 * remoteness_s + 0.3 * g_ia),
    statut  = if_else(runif(n()) < p_fonct, "fonctionnaire", "contractuel"),
    statut  = factor(statut, levels = c("fonctionnaire", "contractuel")),
    # corps (simplified)
    corps = sample(c("instituteur", "instituteur adjoint", "vacataire"),
                   n(), replace = TRUE, prob = c(0.5, 0.35, 0.15)),
    anciennete = pmax(0L, round(rnorm(n(),
                   mean = if_else(statut == "fonctionnaire", 12, 5), sd = 6))),
    # LATENT attendance propensity (consumed by V3 to generate observed waves)
    att_logit = params$att_base_logit -
                params$b_remote_att * remoteness_s +
                params$b_gov_att   * g_ia +
                params$b_fonct_att * (statut == "fonctionnaire") +
                rnorm(n(), 0, params$sd_att),
    attendance_prop = plogis(att_logit) ) |>
  select(enseignant_id, ecole_id, ief_id, ia_id, region, milieu, genre, statut,
         corps, anciennete, attendance_prop)

cat("Nombre d'enseignants simulés :", nrow(enseignants), "\n")
Nombre d'enseignants simulés : 15739 

6 Niveau latent des élèves (moyenne par école)

# Mean teacher attendance per school feeds the pupil-ability latent.
att_school <- enseignants |>
  group_by(ecole_id) |>
  summarise(att_school = mean(attendance_prop), .groups = "drop")

ecoles <- ecoles |>
  left_join(att_school, by = "ecole_id") |>
  mutate(
    ptr_z = as.numeric(scale(ptr)),
    # latent school-mean ability (standardized) — the "truth" V4 will recover
    ability_school = params$b_quality_ab * quality +
                     params$b_ptr_ab     * ptr_z +
                     params$b_att_ab     * as.numeric(scale(att_school)) +
                     params$b_remote_ab  * remoteness_s +
                     params$b_ief_ab     * ief_effect +
                     rnorm(n(), 0, params$sd_school_ab) )

7 Centres préscolaires (alimente le V5)

set.seed(503)
prescolaire <- tibble(
  centre_id = sprintf("P%05d", seq_len(params$n_prescolaire)),
  region    = sample(regions$region, params$n_prescolaire, replace = TRUE, prob = regions$poids)
) |>
  left_join(select(regions, region, remoteness), by = "region") |>
  mutate(
    milieu = if_else(runif(n()) < (0.75 - 0.65 * remoteness), "urbain", "rural"),
    milieu = factor(milieu, levels = c("urbain", "rural")),
    # type: CTP (community) dominates rural; private concentrated urban
    u = runif(n()),
    type = case_when(
      milieu == "urbain" & u < 0.45 ~ "public",
      milieu == "urbain" & u < 0.75 ~ "CTP",
      milieu == "urbain"            ~ "prive",
      u < 0.40                      ~ "public",
      u < 0.95                      ~ "CTP",
      TRUE                          ~ "prive"),
    type = factor(type, levels = c("public", "CTP", "prive")),
    mu_enrol = case_when(type == "public" ~ 70, type == "CTP" ~ 45, TRUE ~ 60),
    enrol = pmax(round(rlnorm(n(), log(mu_enrol) - 0.4^2/2, 0.4)), 8L) ) |>
  select(centre_id, region, milieu, type, remoteness, enrol)

count(prescolaire, type) |> knitr::kable(caption = "Centres préscolaires par type.")
Centres préscolaires par type.
type n
public 1489
CTP 1512
prive 499

8 Population de référence (dénominateur des taux de scolarisation)

# The spine produces the NUMERATOR (enrolment via schools) but not the
# DENOMINATOR (school-age population). We simulate a reference population 6-11
# by region and gender, CALIBRATED so that the resulting gross enrolment ratio
# (GER) falls in a plausible band (target lower where remoteness is higher).
# This is an explicit calibration assumption: the spine MANUFACTURES a coherent
# numerator/denominator pair, it does not measure one — documented as such.

enrol_region <- ecoles |>
  group_by(region) |>
  summarise(inscrits_filles  = sum(eleves_filles),
            inscrits_garcons = sum(eleves_garcons),
            inscrits_total   = sum(enrol), .groups = "drop") |>
  left_join(select(regions, region, remoteness), by = "region")

set.seed(504)
population_reference <- enrol_region |>
  mutate(
    ger_cible  = pmin(1.05, params$ger_cible_base - params$b_remote_ger * remoteness),
    # back out total population from enrolment / target GER (+ mild noise)
    pop_total  = round(inscrits_total / (ger_cible * runif(n(), 0.97, 1.03))),
    pop_filles = round(pop_total * params$part_filles_pop),
    pop_garcons = pop_total - pop_filles,
    part_age_officiel = params$part_age_officiel ) |>
  select(region, remoteness, pop_6_11_total = pop_total,
         pop_6_11_filles = pop_filles, pop_6_11_garcons = pop_garcons,
         part_age_officiel)

# quick coherence peek: implied national GER should sit near the target band
implied_ger <- sum(enrol_region$inscrits_total) / sum(population_reference$pop_6_11_total)
cat("TBS national implicite :", round(100 * implied_ger, 1), "%\n")
TBS national implicite : 80.4 %

9 Contrôles de cohérence

# 1. PTR should rise with remoteness (inequity), and be lower under reform.
ecoles |>
  group_by(reform) |>
  summarise(ptr_moyen = mean(ptr), .groups = "drop") |>
  mutate(reform = if_else(reform == 1L, "IA réformée", "IA standard")) |>
  knitr::kable(digits = 1, caption = "PTR moyen selon la réforme de déconcentration.")
PTR moyen selon la réforme de déconcentration.
reform ptr_moyen
IA standard 46.0
IA réformée 38.4

Le ratio élèves-maître croît avec l’enclavement (sous-dotation des zones reculées).

ggplot(ecoles, aes(remoteness_s, ptr)) +
  geom_point(alpha = 0.15) + geom_smooth(method = "loess", se = FALSE) +
  labs(x = "Enclavement de l'école", y = "Ratio élèves-maître") + theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

Le ratio élèves-maître croît avec l’enclavement (sous-dotation des zones reculées).
cat("Corr(présence enseignante, gouvernance IA) =",
    round(cor(enseignants$attendance_prop,
              ia$g_ia[match(enseignants$ia_id, ia$ia_id)]), 2), "\n")
Corr(présence enseignante, gouvernance IA) = 0.71 
cat("Corr(niveau latent école, qualité école)   =",
    round(cor(ecoles$ability_school, ecoles$quality), 2), "\n")
Corr(niveau latent école, qualité école)   = 0.86 
cat("Présence moyenne urbain vs rural          :",
    round(tapply(enseignants$attendance_prop, enseignants$milieu, mean), 3), "\n")
Présence moyenne urbain vs rural          : 0.81 0.758 

10 Écriture des fichiers canoniques et contrat de données

write_csv(regions,     file.path(params$out_dir, "regions.csv"))
write_csv(ia,          file.path(params$out_dir, "ia.csv"))
write_csv(ief,         file.path(params$out_dir, "ief.csv"))
write_csv(ecoles,      file.path(params$out_dir, "ecoles.csv"))
write_csv(enseignants, file.path(params$out_dir, "enseignants.csv"))
write_csv(prescolaire, file.path(params$out_dir, "prescolaire_centres.csv"))
write_csv(population_reference, file.path(params$out_dir, "population_reference.csv"))

tibble(
  fichier = c("regions.csv","ia.csv","ief.csv","ecoles.csv","enseignants.csv",
              "prescolaire_centres.csv","population_reference.csv"),
  lignes  = c(nrow(regions),nrow(ia),nrow(ief),nrow(ecoles),nrow(enseignants),
              nrow(prescolaire),nrow(population_reference))
) |> knitr::kable(caption = "Fichiers écrits.")
Fichiers écrits.
fichier lignes
regions.csv 14
ia.csv 16
ief.csv 55
ecoles.csv 2500
enseignants.csv 15739
prescolaire_centres.csv 3500
population_reference.csv 14

Contrat de données (ce que chaque volet consomme) :

  • V1 — Allocation : ecoles.csv (ptr, enrol, reform, g_ia, remoteness_s) + enseignants.csv. Le drapeau reform est le traitement dont V1 estime l’effet sur le PTR et son équité.
  • V2 — Décentralisation : ia.csv/ief.csv (g_ia, reform, ief_effect), ecoles.csv (ability_school, quality, att_school, part_filles), enseignants.csv (genre, statut) — décomposition multiniveau (variance IEF réelle via ief_effect), effets sur qualité/efficience/équité dont genre (gouvernance → accès des filles, avec interaction enclavement), et goulets via NLP.
  • V3 — Présence : enseignants.csv (attendance_prop) — V3 génère 3 vagues bruitées d’observation de présence à partir de cette propension, puis reconstruit le panel.
  • V4 — Acquis : ecoles.csv (ability_school) + covariables élèves (genre, milieu, langue maternelle, inclusion) que V4 simule, avec DIF injecté, à partir du niveau latent.
  • V5 — Préscolaire : prescolaire_centres.csv — base de sondage (extension sénégalaise du Projet 21) + pilote psychométrique.
  • Transversal : tous les fichiers, dont population_reference.csv (dénominateur) et le détail genre de ecoles.csv (eleves_filles, eleves_garcons) — moteur d’indicateurs (TBS/TNS, indice de parité, ratio élèves-maître, dotation, concentration).

Le socle fixe la « vérité » ; chaque volet la mesure à sa manière. C’est cette colonne vertébrale partagée qui rend la série intégrée et articulée.

11 Synthèse

Le socle génère un univers éducatif sénégalais structurellement proche de la réalité — 14 régions, 16 inspections d’académie (Dakar en comptant trois), 55 IEF, 2 500 écoles élémentaires, près de 15 000 postes d’enseignants et 3 500 centres préscolaires (public, Cases des tout-petits, privé). Le ratio élèves-maître se distribue autour d’une médiane proche de 44, cohérente avec un système sous tension et hétérogène ; une population de référence 6–11 ans, par région et par genre, est simulée pour servir de dénominateur aux taux de scolarisation, calibrée pour que le TBS tombe dans une fourchette plausible (plus faible dans les régions enclavées).

Les contrôles confirment que la couche latente est correctement injectée : la présence enseignante est fortement liée à la gouvernance de l’IA et supérieure en milieu urbain (0,81) qu’en rural (0,76) ; le niveau latent des écoles suit étroitement leur qualité (r ≈ 0,86). Ces corrélations ne sont pas des résultats en soi — ce sont des garde-fous attestant que l’univers se comporte comme spécifié, condition pour que les volets en aval retrouvent des effets réels plutôt que du bruit. La vraie proportion nationale d’enfants « on-track » (~0,52) et la distribution des effectifs par domaine servent de références connues que les volets en aval devront retrouver — c’est la fonction de ce socle : fixer une vérité mesurable pour ce bac à sable de demonstration.

Note Le premier garde-fou porte sur la réforme de déconcentration (drapeau reform) ciblant certaines IA et joue le rôle de quasi-expérimentation : les écoles des IA réformées affichent un PTR sensiblement plus favorable (38,4 contre 46,0), soit ~16,5 % d’écart brut. Le signal-clé du volet 1 est donc bien présent et d’une ampleur exploitable — franche sans être caricaturale. L’univers ainsi fixé constitue la vérité partagée de la série : chaque volet en mesurera une facette à partir des mêmes fichiers canoniques.

Note de transparence : en simulant le dénominateur (population) après le numérateur (effectifs), le socle fabrique une cohérence numérateur/dénominateur plutôt qu’il ne la mesure ; les taux de scolarisation qui en découlent sont donc des grandeurs de démonstration, calibrées, à lire comme telles.