Statistiques sur Parcoursup

Étude des données des affectations post-bac pour la rentrée 2021, qui apportent beaucoup de nouveautés : nouveau bac, nouvelle plateforme Parcoursup et nouvelle filière MP2I (maths-physique-informatique) en CPGE

Chargement des données

Chargeons les données sur https://data.enseignementsup-recherche.gouv.fr/pages/home/?flg=fr, en ne conservant que les colonnes les plus intéressantes et en les renommant pour plus de clarté :

In [13]:
import pandas as pd
import plotly.express as px

df = pd.read_csv("https://data.enseignementsup-recherche.gouv.fr/explore/dataset/fr-esr-parcoursup/download/?format=csv&timezone=Europe/Berlin&lang=fr&use_labels_for_header=true&csv_separator=%3B", sep=";") \
    .iloc[:, [110, 3, 5, 7, 8, 9, 17, 45, 60, 61, 62, 63, 101, 107]] \
    .rename(columns={"Effectif total des candidats pour une formation": "Candidats", "Dont effectif des admis néo bacheliers sans mention au bac": "Sans Mention", "Dont effectif des admis néo bacheliers avec mention Assez Bien au bac": "Mention Assez Bien", "Dont effectif des admis néo bacheliers avec mention Bien au bac": "Mention Bien", "Dont effectif des admis néo bacheliers avec mention Très Bien au bac": "Mention Très Bien", "Rang du dernier appelé du groupe 1": "Rang dernier appelé", "Taux d’accès des candidats ayant postulé à la formation (ratio entre le dernier appelé et le nombre vœux PP)": "Taux d'accès", "LIB_FOR_VOE_INS": "Filière", "Effectif total des candidats ayant accepté la proposition de l’établissement (admis)": "Effectif"}) \
    .dropna()
df = df.query("Effectif != 0") # supprime les formations avec 0 élève
df.loc[df["Filière"].str.contains("Sportive"), "Filière"] = "STAPS"
df.loc[df["Filière"] == "Concours Première année", "Filière"] = "Concours véto"
df["Filière"] = df["Filière"].str.slice(0, 30)  # raccourcir les noms de filières
df["Taux d'accès"] = df["Taux d'accès"]*df["Effectif"]

Pour la suite, je créé df_filiere qui agrège les données par filière et df_cpge qui contient seulement les filières de CPGE :

In [14]:
mentions = ["Sans Mention", "Mention Assez Bien", "Mention Bien", "Mention Très Bien"]
col = mentions + ["Taux d'accès", "Effectif", "Candidats"]
df_filiere = df.groupby("Filière").agg(dict({s: "sum" for s in col}))
df_filiere["Nombre"] = df.groupby("Filière").size() # nombre de classes de chaque filière
df_filiere[mentions] = df_filiere[mentions].div(df_filiere[mentions].sum(axis=1), axis=0) # pourcentage de mentions par filière
df_filiere["Taux d'accès"] /= df_filiere["Effectif"]
df_cpge = df_filiere[df_filiere.index.str.contains("CPGE")]

Statistiques générales

In [15]:
df.describe()
Out[15]:
Candidats Effectif Sans Mention Mention Assez Bien Mention Bien Mention Très Bien Rang dernier appelé Taux d'accès
count 11513.000000 11513.000000 11513.000000 11513.000000 11513.000000 11513.000000 11513.000000 11513.000000
mean 887.979067 49.574394 9.433423 13.487796 9.322158 3.656649 401.738383 2877.289151
std 1374.959205 81.589291 18.557587 25.022104 21.329345 12.872908 973.015658 5915.978998
min 3.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 2.000000
25% 199.000000 15.000000 2.000000 3.000000 2.000000 0.000000 31.000000 610.000000
50% 421.000000 27.000000 5.000000 7.000000 4.000000 1.000000 92.000000 1144.000000
75% 934.000000 47.000000 10.000000 13.000000 9.000000 2.000000 343.000000 2448.000000
max 18190.000000 1569.000000 344.000000 532.000000 556.000000 444.000000 15836.000000 145200.000000

On observe que l'effectif moyen dans une formation est environ 50, avec un maximum de 1569 pour la formation suivante :

In [16]:
df.iloc[[df["Effectif"].argmax()]]
Out[16]:
Filière Établissement Département de l’établissement Académie de l’établissement Commune de l’établissement Sélectivité Candidats Effectif Sans Mention Mention Assez Bien Mention Bien Mention Très Bien Rang dernier appelé Taux d'accès
1591 Licence - Portail Droit - parc Université Toulouse 1 Capitole Haute-Garonne Toulouse Toulouse formation non sélective 8385.0 1569.0 344.0 532.0 329.0 71.0 6215.0 112968.0

Effectifs

Voici les 20 formations avec le plus gros effectif :

In [17]:
df_gros = df_filiere.sort_values("Effectif", ascending=False)[:20]
px.pie(df_gros, values="Effectif", names=df_gros.index, title="Pourcentage des effectifs par formation") \
  .show(renderer="notebook")

Filière de CPGE avec le plus de classes :

In [21]:
df_cpge_gros = df_cpge.sort_values("Nombre", ascending=False)[:11]
px.pie(df_cpge_gros, values="Nombre", names=df_cpge_gros.index, title="Nombre de classes par filière de CPGE") \
  .show(renderer="notebook")

Nombre de candidatures

Voici les filières avec un nombre de candidature par place le plus élevé :

In [22]:
df_candidats = df_filiere[["Candidats"]].div(df_filiere["Effectif"], axis=0).sort_values(by="Candidats", ascending=False)[:10]
px.bar(df_candidats, title="Nombre de candidatures par place") \
  .show(renderer="notebook")
In [31]:
df_candidats = df_cpge_gros[["Candidats"]].div(df_cpge_gros["Effectif"], axis=0).sort_values(by="Candidats", ascending=False)
px.bar(df_candidats, title="Nombre de candidatures par place en CPGE") \
  .show(renderer="notebook")

Pourcentage de mentions au bac

In [32]:
df_m = df_filiere[mentions].loc[df_gros.index].sort_values(by="Mention Très Bien", ascending=False)
px.bar(df_m, title="Pourcentage de mentions par formation") \
  .show(renderer="notebook")
In [33]:
df_m = df_cpge_gros[mentions].loc[df_cpge_gros.index].sort_values(by="Mention Très Bien", ascending=False)
px.bar(df_m, title="Pourcentage de mentions par filière de CPGE") \
  .show(renderer="notebook")

Taux d'accès

In [36]:
px.bar(df_gros["Taux d'accès"].sort_values(), title="Taux d'accès moyen (%) des plus grosses formations") \
  .show(renderer="notebook")
In [37]:
px.bar(df_cpge_gros["Taux d'accès"].sort_values(), title="Taux d'accès moyen (%) de chaque filière de CPGE") \
  .show(renderer="notebook")