Source code for src.ml.prediction_reussite


# Imports
from ..shared_import import *
from ..general import *
import pandas as pd
import numpy as np
import joblib

from sklearn.model_selection import train_test_split  # Pour diviser les données
from sklearn.metrics import accuracy_score  # Pour évaluer le modèle
from sklearn.linear_model import LogisticRegression  # Importer la régression logistique
from sklearn.ensemble import RandomForestRegressor  # Importer la forêt aléatoire

# Constantes
MODELS_FOLDER: str = f"{ROOT}/models"
os.makedirs(MODELS_FOLDER, exist_ok=True)

## Objectif : faire un modèle de prédiction du taux de réussite d'un étudiant (score entre 0 et 1)
# Variables à utiliser
VARIABLES_UTILES: list[str] = [		# Variables qualitatives
	"gd_discipline_lib",
	"discipline_lib",
	"sect_disciplinaire_lib",
	"serie_bac_lib",
	"age_au_bac_lib",
	"sexe_lib",
	"mention_bac_lib",
]

# Fonction pour entrainer le modèle
[docs] @stp.handle_error(error_log=stp.LogLevels.ERROR_TRACEBACK) def entrainer_modeles() -> None: """ Entraine le modèle de prédiction du taux de réussite d'un étudiant - Récupération des données - Préparation des données - Entrainement du modèle - Sauvegarde du modèle """ # Récupération des données json_data: list[dict] = get_all_data() data: pd.DataFrame = pd.DataFrame(json_data) data["taux_reussite"] = data["reussite_3_4_ans"] / data["effectif_neobacheliers_reussite"] # Calcul du taux de réussite (nombre de réussite en 3-4 ans / nombre d"étudiants) # Ignorer les lignes avec des valeurs manquantes data = data.dropna() # Préparation des données X: pd.DataFrame = data[VARIABLES_UTILES] # Variables indépendantes y: pd.Series = data["taux_reussite"] # Variable dépendante # Convert continuous target to binary for logistic regression y_binary: pd.Series = (y > 0.5).astype(int) # Convertir les variables qualitatives en variables numériques X_encoded: pd.DataFrame = pd.get_dummies(X) # Sauvegarder les colonnes pour pouvoir les réutiliser plus tard colonnes: list[str] = X_encoded.columns.tolist() joblib.dump(colonnes, f"{MODELS_FOLDER}/colonnes.pkl") # Diviser les données en ensembles d"entraînement et de test X_train: pd.DataFrame X_test: pd.DataFrame y_train: pd.Series y_test: pd.Series X_train, X_test, y_train, y_test = train_test_split(X_encoded, y, test_size=0.2, random_state=42) # Define categorial_y_test categorial_y_test: pd.Series = y_test.apply(lambda x: 1 if x > 0.5 else 0) # Créer le modèle de régression logistique et l'entraîner model_logistic: LogisticRegression = LogisticRegression() model_logistic.fit(X_train, y_binary[y_binary.index.isin(y_train.index)]) # Use binary values for training # Évaluer le modèle de régression logistique y_pred_logistic: np.ndarray = model_logistic.predict_proba(X_test)[:, 1] # Probabilités pour la classe positive accuracy_logistic: float = accuracy_score(categorial_y_test, np.where(y_pred_logistic > 0.5, 1, 0)) stp.info(f"Accuracy (Logistic Regression): {accuracy_logistic}") # Créer le modèle de forêt aléatoire et l'entraîner model_rf: RandomForestRegressor = RandomForestRegressor(random_state=42) model_rf.fit(X_train, y_train) # Évaluer le modèle de forêt aléatoire y_pred_raw_rf: np.ndarray = model_rf.predict(X_test) y_pred_rf: np.ndarray = np.where(y_pred_raw_rf > 0.5, 1, 0) accuracy_rf: float = accuracy_score(categorial_y_test, y_pred_rf) stp.info(f"Accuracy (Random Forest): {accuracy_rf}") # Sauvegarde des modèles joblib.dump(model_logistic, f"{MODELS_FOLDER}/logistic.pkl") joblib.dump(model_rf, f"{MODELS_FOLDER}/rf.pkl")
# Fonction pour charger le modèle
[docs] def charger_modele(model_name: Literal["logistic", "rf"]) -> tuple[Any, list[str]]: """ Charge le modèle de prédiction du taux de réussite d"un étudiant - Essaie de charger le modèle - Si le modèle n"est pas trouvé, entraine le modèle Returns: tuple[Any, list[str]]: Le modèle et la liste des colonnes pour l'encodage """ model_path: str = f"{MODELS_FOLDER}/{model_name}.pkl" colonnes_path: str = f"{MODELS_FOLDER}/colonnes.pkl" try: model: Any = joblib.load(model_path) except FileNotFoundError: entrainer_modeles() model: Any = joblib.load(model_path) colonnes: list[str] = joblib.load(colonnes_path) return model, colonnes
# Fonction pour prédire la reussite d"un étudiant
[docs] @stp.handle_error() def predire_reussite(etudiant: dict, model_name: Literal["logistic", "rf"]) -> float: """ Prédit le taux de réussite d"un étudiant - Chargement du modèle (si pas déjà chargé) - Prédiction Examples: >>> predire_reussite({ "gd_discipline": "Lettres, langues et sciences humaines", "discipline": "Langues", "sect_disciplinaire": "Langues et littératures étrangères", "serie_bac": "BAC STMG", "age_au_bac": "A l'heure ou en avance", "sexe": "Homme", "mention_bac": "Très bien", }, "logistic" ) 0.5 """ model: Any colonnes: list[str] model, colonnes = charger_modele(model_name) # Préparation des données etudiant_df: pd.DataFrame = pd.DataFrame([etudiant]) # Wrap the dictionary in a list etudiant_encoded: pd.DataFrame = pd.get_dummies(etudiant_df) # S'assurer que toutes les colonnes nécessaires sont présentes for col in colonnes: if col not in etudiant_encoded.columns: etudiant_encoded[col] = 0 # Réorganiser les colonnes dans le même ordre que lors de l'entrainement etudiant_encoded = etudiant_encoded[colonnes] # Prédiction if isinstance(model, LogisticRegression): raw_prediction: float = model.predict_proba(etudiant_encoded)[:, 1][0] # Get probability for the positive class elif isinstance(model, RandomForestRegressor): raw_prediction: float = model.predict(etudiant_encoded)[0] else: raise ValueError(f"Modèle inconnu: {type(model)}") return raw_prediction
[docs] @app.route("/ml/prediction_reussite", methods=["GET"]) def prediction_reussite() -> dict: """ Prédit le taux de réussite d'un étudiant à partir des données fournies. Cette fonction reçoit les informations d'un étudiant via des paramètres de requête et utilise un modèle préalablement entraîné pour prédire le taux de réussite. Args: gd_discipline (str): La grande discipline de l'étudiant. discipline (str): La discipline de l'étudiant. sect_disciplinaire (str): Le secteur disciplinaire de l'étudiant. serie_bac (str): La série du baccalauréat de l'étudiant. age_au_bac (str): L'âge de l'étudiant au moment du baccalauréat. sexe (str): Le sexe de l'étudiant. mention_bac (str): La mention obtenue au baccalauréat. model_name (Literal["logistic", "rf"]): Le nom du modèle à utiliser. Returns: dict: Un dictionnaire contenant le taux de réussite prédit. Examples: >>> requests.get(f"http://localhost:5000/ml/prediction_reussite?gd_discipline=Lettres, langues et sciences humaines&discipline=Langues&sect_disciplinaire=Langues et littératures étrangères&serie_bac=BAC STMG&age_au_bac=A l'heure ou en avance&sexe=Homme&mention_bac=Très bien&model_name=logistic").json() {'taux_reussite': 0.24319507790674746} """ etudiant: dict = { "gd_discipline": request.args.get("gd_discipline"), "discipline": request.args.get("discipline"), "sect_disciplinaire": request.args.get("sect_disciplinaire"), "serie_bac": request.args.get("serie_bac"), "age_au_bac": request.args.get("age_au_bac"), "sexe": request.args.get("sexe"), "mention_bac": request.args.get("mention_bac"), } for key, value in etudiant.items(): if value is None: raise ValueError(f"Le paramètre {key} est requis") model_name: str = request.args.get("model_name", "logistic") proba: float = predire_reussite(etudiant, model_name) return {"taux_reussite": proba}