Données de projection des effectifs scolaires
Licence : Licence Ouverte / Open Licence version 2.0
Fréquence de mise à jour : punctual

Données issues de [l'étude du ministère de l'éducation](https://www.education.gouv.fr/depp/projections-d-effectifs-d-eleves-dans-les-premier-et-second-degres-horizon-2035-504275) dans un format interopérable.

Code d'extraction des données (après avoir téléchargé les fichiers par académie et les avoir placés dans un dossier \`projections\_educnat/\`) :

```python
import pandas as pd
import openpyxl
import os

degres = {"1D": "Premier", "2D": "Second"}
cols = ["niveau", "2025", "2026", "2027", "2028", "2029", "2030", "2031", "2032", "2033", "2034", "2035"]
final = []

for file in [f for f in os.listdir("projections_educnat/") if f.endswith(".xlsx")]:
    print(file)
    wb = openpyxl.load_workbook(
        f"projections_educnat/{file}",
        read_only=True,
    )
    keep = [title for s in wb.worksheets if "ACAD" not in (title := s.title)]
    for sheet in keep:
        print(sheet)
        dep = sheet[:3] if sheet.startswith("97") else sheet[1:3]
        degre = sheet[-2:]
        raw = pd.read_excel(f"projections_educnat/{file}", sheet_name=sheet)
        assert len(raw.columns) == len(cols)
        academie = raw.columns[0].split("Académie")[-1][3:].lstrip(" ")
        raw.columns = cols
        data_rows = raw.loc[
            ((raw["niveau"].notna()) & (raw["2025"].notna()))
            | (raw["niveau"].isin({"PUBLIC", "PRIVE SOUS CONTRAT", "Total PUBLIC et PRIVE SOUS CONTRAT"}))
        ].reset_index(drop=True)
        data_rows
        secteur = []
        current_secteur = None
        for idx, row in data_rows.iterrows():
            if row["niveau"] in {"PUBLIC", "PRIVE SOUS CONTRAT"}:
                current_secteur = row["niveau"].title()
            elif row["niveau"] == "Total PUBLIC et PRIVE SOUS CONTRAT":
                current_secteur = pd.NA
            if idx > 0 and current_secteur is None:
                raise ValueError
            secteur.append(current_secteur)
        data_rows["secteur"] = secteur
        data_rows["degre"] = degres[degre]
        data_rows = data_rows.loc[
            (data_rows["2028"].notna()) & (data_rows["secteur"].notna())
        ].reset_index(drop=True)
        data_rows["code_departement"] = dep
        data_rows["academie"] = academie
        first_cols = ["code_departement", "academie", "secteur", "degre"]
        final.append(data_rows[first_cols + [c for c in data_rows.columns if c not in first_cols]])

final = pd.concat(final, ignore_index=True)
for col in final.columns:
    if col.startswith("20"):
        final[col] = final[col].astype(int)
final.to_csv("projections_educnat/projections_departement.csv", index=False)
```