Repérer et traiter les valeurs manquantes et les doublons

Pour repérer et traiter les valeurs manquantes et les doublons, commencez par mesurer ce qui manque et par comprendre ce qui se répète. Une case vide ne vaut pas zéro ; deux élèves peuvent partager les mêmes caractéristiques. Supprimer ou remplir automatiquement ces informations risque donc de modifier le sens du tableau. Nous allons établir un diagnostic avec pandas, comparer plusieurs décisions et conserver une trace des transformations.
Avant de commencer. Les cellules Python sont modifiables et exécutables dans cette page, sauf la préparation des bibliothèques. Exécutez-les dans l’ordre : Python se charge au premier lancement, puis les cellules partagent la même mémoire. Un rechargement de la page ou un redémarrage ouvre une nouvelle session. Pour travailler localement, suivez le guide Python, uv, VS Code et Jupyter et choisissez le noyau de votre environnement .venv.
Préparation des bibliothèques — cellule non modifiable. Dans le notebook local, cette cellule vérifie pandas et openpyxl et utilise uv seulement pour les paquets absents, dans le Python du noyau sélectionné. Les paquets déjà disponibles ne sont pas réinstallés. Dans cette page, le moteur du navigateur prépare les bibliothèques au premier lancement ; il n’exécute pas uv sur votre ordinateur.
# Vérifier les bibliothèques avant toute installation.
from importlib.util import find_spec
import subprocess
import sys
manquants = [nom for nom in ("pandas", "openpyxl") if find_spec(nom) is None]
if manquants:
subprocess.run(
["uv", "pip", "install", "--python", sys.executable, *manquants],
check=True,
)
else:
print("pandas et openpyxl sont déjà installés.")pandas et openpyxl sont déjà installés.Sommaire
1. Charger une vue adaptée à la tâche
La préparation commence par le choix des colonnes utiles. Dans le jeu de régression, la cible est Exam_Score et la colonne Result est exclue dès la lecture. Nous conservons les 19 autres variables pour examiner les absences et les répétitions. La fonction read_excel charge la feuille Données dans un DataFrame, le tableau de pandas.
# Lire le classeur placé à côté du notebook.
import pandas as pd
fichier = "StudentPerformanceFactors_Reg_Classif.xlsx"
df = pd.read_excel(
fichier, sheet_name="Données", engine="openpyxl",
usecols=lambda nom: nom != "Result",
)
# Pour travailler en CSV, remplacez la lecture Excel par :
# df = pd.read_csv("StudentPerformanceFactors_Reg_Classif.csv",
# usecols=lambda nom: nom != "Result")
print("Observations :", len(df))
print("Colonnes :", df.shape[1])Observations : 6607
Colonnes : 20On obtient 6 607 observations et 20 colonnes. Pour choisir le CSV, remplacez le bloc pd.read_excel(...) par les deux lignes de l’alternative pd.read_csv(...), en retirant leur caractère #. Il n’est pas nécessaire de lire puis de réunir les deux fichiers. Ils portent les mêmes observations, dans le même ordre.
Gardez le fichier d’origine intact. Les noms completes, documentees et atelier désigneront des résultats distincts. Cela permet de comparer une décision à la source et de revenir sur un choix sans devoir retrouver un fichier écrasé.
2. Repérer et compter les valeurs manquantes
Une valeur manquante est une information absente pour une observation et une variable. pandas la représente notamment par NaN ou pd.NA, selon le type de la colonne. Utilisez isna() pour la repérer : cette méthode produit un tableau de booléens, True aux emplacements absents et False ailleurs. La documentation sur les données manquantes explique ces représentations.
Une absence se distingue d’une valeur observée : zéro séance de tutorat est un nombre de séances connu ; une case absente signifie que ce nombre n’est pas renseigné. De même, la réponse No à une activité reste une catégorie connue. Remplacer toutes les absences par zéro ou par No introduirait une affirmation que le fichier ne fournit pas.
Voir les valeurs manquantes dans huit observations
Affichons les huit premières lignes incomplètes et les trois colonnes concernées. La sélection garde l’ordre du fichier. L’index du tableau d’origine est numéroté à partir de zéro. Le filtrage conserve ces numéros : l’extrait commence donc à l’index 33 et présente des valeurs discontinues. Cet index sert à retrouver une ligne dans le tableau chargé ; il ne constitue pas un identifiant d’élève.
# Examiner les absences réellement présentes dans le fichier.
colonnes_absentes = [
"Teacher_Quality", "Parental_Education_Level", "Distance_from_Home"
]
lignes_incompletes = df.isna().any(axis=1)
print(df.loc[lignes_incompletes, colonnes_absentes].head(8).to_string()) Teacher_Quality Parental_Education_Level Distance_from_Home
33 Medium College NaN
127 NaN High School Far
240 Medium NaN Moderate
275 Medium High School NaN
316 Medium College NaN
359 Medium High School NaN
380 Medium High School NaN
396 NaN College ModerateLa ligne d’index 33 ne renseigne pas la distance ; celle d’index 127 ne renseigne pas la qualité de l’enseignant ; celle d’index 240 ne renseigne pas le niveau d’études des parents. Le même affichage NaN signale l’absence dans des colonnes différentes. Il n’indique ni sa cause ni la valeur qui aurait dû être saisie.
Compter des cellules et des lignes
Avec isna().sum(), on compte les valeurs manquantes de chaque colonne. Pour repérer les lignes concernées, any(axis=1) teste si une absence apparaît quelque part sur la ligne. Le pourcentage ci-dessous divise chaque effectif par les 6 607 observations ; il ne prend pas les seules lignes incomplètes pour dénominateur.
# Compter par colonne, puis distinguer cellules et observations.
absences = df.isna()
effectifs = absences.sum()
bilan = pd.DataFrame({
"Absences": effectifs,
"Pourcentage": (effectifs / len(df) * 100).round(2),
})
print(bilan.loc[bilan["Absences"] > 0].to_string())
print("Cellules manquantes :", int(absences.sum().sum()))
print("Observations touchées :", int(absences.any(axis=1).sum())) Absences Pourcentage
Teacher_Quality 78 1.18
Parental_Education_Level 90 1.36
Distance_from_Home 67 1.01
Cellules manquantes : 235
Observations touchées : 229| Variable | Absences | Part des observations |
|---|---|---|
Teacher_Quality | 78 | 1,18 % |
Parental_Education_Level | 90 | 1,36 % |
Distance_from_Home | 67 | 1,01 % |
On compte 235 cellules manquantes. Elles concernent 229 observations, soit environ 3,47 % des 6 607 lignes. Les deux nombres diffèrent parce qu’une même observation peut cumuler des valeurs manquantes. Toutes les colonnes numériques de cette vue sont renseignées : aucune valeur manquante n’y est donc à imputer dans cette version du fichier.

Avant d’interpréter ce bilan, vérifiez les conventions de saisie de votre source. Une chaîne contenant des espaces ou un code comme ? peut nécessiter une règle de lecture spécifique ; isna() ne découvre pas à lui seul tous les codes métier. Ici, nous comptons les absences reconnues lors de la lecture du classeur fourni. Le tableau seul ne permet pas d’en établir la cause.
3. Choisir un traitement des valeurs manquantes
Traiter les valeurs manquantes nécessite une décision justifiée. Peut-on retrouver l’information dans une source fiable ? La variable est-elle nécessaire à l’analyse ? Les absences se concentrent-elles sur un groupe particulier ? Un faible pourcentage de valeurs manquantes ne suffit pas à répondre. Supprimer des lignes peut réduire la quantité d’information et modifier la population étudiée ; remplacer une valeur peut créer une ressemblance artificielle.
L’imputation consiste à remplacer une information manquante par une valeur choisie ou estimée. Le choix de la règle dépend du sens de la variable et de l’objectif de l’analyse.
On peut aussi écarter une variable de l’analyse lorsqu’elle est inutilisable ou peu pertinente. Cela retire une colonne, alors que supprimer des observations retire des lignes : les pertes d’information ne sont pas les mêmes. Ce choix doit être justifié par l’objectif et les informations disponibles.
| Action | Ce qu’elle permet | Limite à garder |
|---|---|---|
| Retrouver la donnée | Corriger depuis une source vérifiée. | Ne pas deviner la réponse. |
| Retirer une ligne | Limiter l’analyse aux observations renseignées. | Documenter les exclusions et leurs effets. |
| Conserver « Inconnu » | Rendre visible l’absence dans une variable catégorielle. | Cette nouvelle modalité n’est pas une information retrouvée. |
| Imputer une variable numérique | Remplacer une valeur manquante par une valeur numérique, par exemple la médiane ou la moyenne. | Respecter l’unité et le domaine des valeurs ; la distribution peut être modifiée. |
| Imputer une variable catégorielle | Utiliser le mode, c’est-à-dire la valeur la plus fréquente, ou un libellé explicite tel que « Inconnu ». | Ne pas calculer la moyenne des noms de catégories. Le remplacement reste une convention. |
| Traiter une absence dans du texte libre | Retrouver le texte à sa source ou en conserver explicitement l’absence. | Ne pas inventer de phrase ni remplacer automatiquement tous les textes absents par le plus fréquent. |
Le type de la variable guide le choix : une durée comme Hours_Studied exprime une quantité ; Teacher_Quality exprime une catégorie. Une chaîne de caractères peut contenir une catégorie, comme Medium, ou du texte libre. Inversement, une catégorie peut être stockée sous forme de code numérique : ce stockage ne lui confère pas le sens d’une quantité. On choisit donc la règle en fonction de la signification du champ, et pas seulement de son type dans pandas.
Mesurer une suppression avant de la décider
dropna() renvoie ici les lignes sans aucune absence. L’argument subset limite la condition à des colonnes précises, comme le précise la documentation de dropna. Comparons deux règles indépendantes :
# Comparer deux règles de suppression sur des copies distinctes.
completes = df.dropna()
avec_qualite = df.dropna(subset=["Teacher_Quality"])
print("Sans aucune absence :", len(completes))
print("Avec Teacher_Quality renseigné :", len(avec_qualite))
print("Lignes retirées par dropna() :", len(df) - len(completes))Sans aucune absence : 6378
Avec Teacher_Quality renseigné : 6529
Lignes retirées par dropna() : 229La suppression générale laisserait 6 378 lignes et en retirerait 229. Exiger une valeur renseignée uniquement pour Teacher_Quality garderait 6 529 lignes. Ces deux choix répondent à des besoins différents. Si une analyse n’utilise pas la distance, son absence ne justifie pas, à elle seule, de retirer une observation de cette analyse.
Aucune de ces sorties ne prouve que les lignes conservées sont représentatives de celles retirées. Un contrôle utile consiste à comparer, lorsque les informations sont disponibles, les caractéristiques des groupes concernés. Ici, le calcul mesure la perte de lignes ; il ne valide pas la suppression comme stratégie pour un futur modèle.

Conserver les valeurs manquantes et leur trace
Nos trois colonnes avec des valeurs manquantes sont catégorielles. Pour une copie destinée à l’exploration, nous pouvons écrire Inconnu aux emplacements absents et ajouter un indicateur d’absence, une colonne booléenne qui conserve leur position initiale. fillna remplace les seules valeurs reconnues comme manquantes ; les catégories déjà renseignées restent inchangées. Voir la documentation de fillna.
# Conserver les lignes et rendre les absences visibles.
documentees = df.copy()
for colonne in colonnes_absentes:
documentees[colonne + "_manquant"] = df[colonne].isna()
documentees[colonne] = df[colonne].fillna("Inconnu")
print("Observations conservées :", len(documentees))
print("Absences initiales :", int(documentees.filter(like="_manquant").sum().sum()))
print("Absences restantes :", int(documentees.isna().sum().sum()))Observations conservées : 6607
Absences initiales : 235
Absences restantes : 0La copie garde 6 607 observations. Ses trois indicateurs signalent toujours les 235 absences initiales, même si les cases du tableau ont désormais un libellé. « Aucune absence restante » signifie donc que l’encodage a changé. Cela ne signifie pas que nous avons retrouvé les informations manquantes.
Le libellé Inconnu pourra devoir être encodé avant l’entraînement, selon le modèle retenu. Il peut également combiner plusieurs raisons d’absence. Garder une trace permet de revoir la préparation lorsque la documentation ou la question de travail évolue.
Imputer une variable catégorielle par sa modalité la plus fréquente
Pour une variable catégorielle, une règle simple consiste à utiliser le mode, c’est-à-dire la modalité la plus fréquente. La documentation scikit-learn sur l’imputation présente notamment cette stratégie, ainsi que la moyenne et la médiane pour des variables numériques.
# Illustrer le remplacement par la modalité la plus fréquente.
mode_qualite = df["Teacher_Quality"].mode().iloc[0]
qualite_imputee = df["Teacher_Quality"].fillna(mode_qualite)
print("Mode observé :", mode_qualite)
print("Valeurs remplacées :", int(df["Teacher_Quality"].isna().sum()))
print("Absences après remplacement :", int(qualite_imputee.isna().sum()))Mode observé : Medium
Valeurs remplacées : 78
Absences après remplacement : 0Dans cette variante, les 78 valeurs manquantes de Teacher_Quality sont remplacées par Medium. La cellule repart de la source : elle ne modifie pas la copie documentees. Ce résultat montre le mécanisme du remplacement ; il ne permet pas d’affirmer que Medium était la valeur réelle pour ces 78 observations. En cas de plusieurs modes, iloc[0] en retiendrait un seul selon l’ordre renvoyé : ce serait encore un choix à documenter.
Pour une évaluation prédictive future, la valeur de remplacement — moyenne, médiane ou mode — doit être calculée à partir des seules données d’entraînement, puis réutilisée sur le jeu de validation ou de test. La calculer sur l’ensemble impliquerait d’utiliser des informations du jeu réservé à l’évaluation : c’est une fuite de données. Un pipeline, qui enchaîne les étapes de préparation et le modèle, permet de respecter cette séparation, comme l’explique scikit-learn dans ses erreurs fréquentes. La cellule précédente reste une illustration descriptive, sans évaluation de modèle.
4. Examiner les doublons avant de les supprimer
Un doublon exact de ligne est une répétition de la ligne entière : toutes les colonnes du jeu étudié ont les mêmes valeurs. Deux lignes qui ne partagent que les heures d’étude, la présence ou quelques autres champs ne sont pas, pour cette seule raison, des doublons. La méthode duplicated() marque par défaut les occurrences supplémentaires, en conservant la première comme référence. L’index n’est pas considéré comme une variable du tableau. Le paramètre subset limite les colonnes comparées : son résultat signale des valeurs communes sur ces champs, sans démontrer à lui seul un doublon de ligne entière. Nous ne l’utilisons pas pour identifier les doublons exacts dans cet exemple. Voir la documentation de duplicated.
duplicated() compare les données telles qu’elles sont enregistrées. Des absences situées dans les mêmes colonnes peuvent être considérées comme correspondantes lors de cette comparaison. Deux lignes présentant les mêmes valeurs connues et les mêmes absences ne prouvent donc pas que les informations non renseignées soient identiques. Le contrôle technique ne remplace pas la vérification de l’origine des enregistrements.
# Rechercher les répétitions sur toutes les colonnes de la vue.
print("Doublons exacts :", int(df.duplicated().sum()))
print("Observations après dédoublonnage :", len(df.drop_duplicates()))Doublons exacts : 0
Observations après dédoublonnage : 6607La source ne contient aucun doublon exact dans le jeu de régression. drop_duplicates() garde donc ses 6 607 lignes. On ne peut pas en déduire qu’une personne n’apparaît jamais à plusieurs reprises : le fichier ne fournit pas d’identifiant d’élève permettant de vérifier son identité.
Deux lignes ayant les mêmes heures d’étude et la même présence peuvent décrire deux élèves différents. À l’inverse, deux enregistrements d’un même élève peuvent différer en raison d’une correction ou d’une période différente. Définissez d’abord ce que représente une ligne et quelles clés devraient être uniques ; ne supprimez pas d’observations uniquement parce que quelques valeurs coïncident.
Distinguer les doublons de ligne des identifiants répétés
Les doublons d’identifiant nécessitent un contrôle supplémentaire : si un ID doit être unique pour chaque observation, sa répétition signale un problème de clé, même lorsque les autres champs diffèrent. Il faut alors examiner les enregistrements et la source avant de décider quoi conserver. Une coïncidence sur un groupe de colonnes ordinaires ne remplace pas ce contrôle d’identité.
Cette règle dépend de ce que représente une ligne. Si une personne apparaît légitimement une fois par période, son identifiant personnel peut se répéter ; c’est le couple « personne et période » qui doit être unique. Le classeur utilisé ici ne fournit pas d’ID d’élève : son index pandas n’en fait pas office. Nous vérifions donc les doublons sur les vingt colonnes de la vue de régression, sans inventer d’identifiant.
Observer des répétitions dont l’origine est connue
Prenons les huit premières observations du jeu de régression et ajoutons une copie intégrale des deux premières : chacune des vingt colonnes est recopiée. Cette opération concerne uniquement atelier. pd.concat réunit les lignes entières ; ignore_index=True attribue un nouvel index de lecture, sans modifier leurs valeurs.
# Recopier deux lignes entières, avec leurs vingt colonnes.
atelier = pd.concat([df.head(8), df.head(2)], ignore_index=True)
print("Lignes de l’atelier :", len(atelier))
print("Répétitions en trop :", int(atelier.duplicated().sum()))
print("Lignes des groupes répétés :", int(atelier.duplicated(keep=False).sum()))
print("Ligne 0 identique à sa copie 8 :", atelier.iloc[0].equals(atelier.iloc[8]))
print("Ligne 1 identique à sa copie 9 :", atelier.iloc[1].equals(atelier.iloc[9]))Lignes de l’atelier : 10
Répétitions en trop : 2
Lignes des groupes répétés : 4
Ligne 0 identique à sa copie 8 : True
Ligne 1 identique à sa copie 9 : TrueL’atelier comporte dix lignes, dont deux sont des copies supplémentaires. Avec keep=False, duplicated marque les quatre lignes appartenant aux deux groupes répétés : les deux premières occurrences et leurs copies. Ces quatre lignes ne sont donc pas en trop. Les deux comparaisons equals confirment que les lignes aux positions 0 et 8, puis celles aux positions 1 et 9, sont identiques sur les vingt colonnes.

Retirer uniquement les copies confirmées
Ici, nous connaissons l’origine des répétitions : nous venons de les ajouter. La méthode drop_duplicates(keep="first") conserve la première occurrence et renvoie un nouveau tableau. Son comportement est décrit dans la documentation de drop_duplicates.
# Retirer les deux copies dont l’origine est connue.
atelier_unique = atelier.drop_duplicates(keep="first")
print("Avant :", len(atelier))
print("Après :", len(atelier_unique))
print("Lignes retirées :", len(atelier) - len(atelier_unique))Avant : 10
Après : 8
Lignes retirées : 2L’extrait retrouve ses huit lignes. Une suppression avec keep=False retirerait toutes les occurrences de chaque groupe, y compris les deux premières lignes : ce serait une autre règle. Lors d’une collecte réelle, vérifiez également les dates, les clés métier et les sources avant de choisir quelle occurrence conserver.
Une imputation peut rendre identiques des lignes auparavant différentes. Pour cette raison, examinez l’origine des répétitions dans la source avant de combler les absences ; ne lancez pas automatiquement un second dédoublonnage après chaque remplacement. Des observations distinctes ne deviennent pas des copies confirmées parce qu’un traitement les a rapprochées.
5. Conserver les décisions et préparer la suite
Garder les deux tâches séparées
La préparation du jeu de classification est contrôlée indépendamment. Il contient la cible Result, déjà fournie avec les étiquettes Success ou Fail, et exclut Exam_Score. La cellule suivante lit ces étiquettes sans les reconstruire. Si vous avez choisi le CSV, utilisez aussi l’alternative commentée dans cette cellule :
# Lire les étiquettes fournies, sans l’autre cible.
df_classification = pd.read_excel(
fichier, sheet_name="Données", engine="openpyxl",
usecols=lambda nom: nom != "Exam_Score",
)
# Alternative CSV :
# df_classification = pd.read_csv("StudentPerformanceFactors_Reg_Classif.csv",
# usecols=lambda nom: nom != "Exam_Score")
print("Cibles Result manquantes :", int(df_classification["Result"].isna().sum()))
print("Doublons exacts :", int(df_classification.duplicated().sum()))Cibles Result manquantes : 0
Doublons exacts : 0Cette cible ne présente aucune absence et le jeu de classification ne contient aucun doublon exact. Si une cible supervisée manquait dans une autre version, lui attribuer la classe majoritaire ne créerait pas une étiquette vérifiée. Il faudrait retrouver l’information ou exclure la ligne de l’entraînement supervisé concerné. La cible n’est donc pas traitée automatiquement comme une entrée incomplète.
Exporter une copie documentée
Conservons la variante qui rend les absences catégorielles explicites. Son export comprend les vingt colonnes du jeu de régression et trois indicateurs d’absence, soit 23 colonnes. index=False évite d’ajouter l’index pandas au CSV. La sortie porte un nom différent de celui du fichier original.
# Enregistrer un résultat distinct du fichier original.
sortie = "Regression_AbsencesDocumentees.csv"
documentees.to_csv(sortie, index=False, encoding="utf-8")
print("Fichier créé :", sortie)
print("Dimensions :", documentees.shape)Fichier créé : Regression_AbsencesDocumentees.csv
Dimensions : (6607, 23)Vous pouvez télécharger le CSV de la copie avec absences documentées, calculé avec le notebook fourni. Il conserve 6 607 observations. Ce fichier aide à poursuivre l’exploration ; il ne remplace ni les données d’origine ni la préparation propre à l’entraînement.
Accompagnez le résultat d’une note simple : fichier source utilisé, colonnes concernées, effectifs avant et après, règle appliquée et limites. Pour notre copie, on écrira que les 235 absences catégorielles ont reçu le libellé Inconnu, que trois indicateurs conservent leur emplacement et qu’aucune ligne source n’a été retirée. Les deux copies supprimées appartiennent uniquement à l’atelier.
Mise en pratique : compter les cumuls et les répétitions
À partir du jeu de données de régression , comptez les observations qui comportent au moins deux valeurs manquantes parmi les trois colonnes concernées. Dans atelier, comptez ensuite les copies supplémentaires. Expliquez pourquoi le nombre de lignes marquées avec ne correspond pas directement au nombre de lignes à retirer.
Voir la correction Python et son interprétation
# Compter le cumul des absences et les copies supplémentaires.
plusieurs_absences = df[colonnes_absentes].isna().sum(axis=1).ge(2)
print("Au moins deux absences :", int(plusieurs_absences.sum()))
print("Copies supplémentaires dans l’atelier :", int(atelier.duplicated().sum()))Au moins deux absences : 6
Copies supplémentaires dans l’atelier : 2Six observations cumulent au moins deux absences. Dans l’atelier, il y a deux copies supplémentaires. Les quatre lignes marquées avec keep=False forment deux groupes de deux occurrences ; conserver une occurrence par groupe retire donc deux lignes.
Erreurs fréquentes
- Confondre absence et zéro. Zéro est une valeur observée ; ne l’utilisez comme remplacement que si le sens du champ le justifie.
- Appliquer
dropna()sans regarder les colonnes. Mesurez d’abord la perte, puis précisez les champs nécessaires à l’analyse. - Utiliser
== NaNpour détecter des valeurs manquantes. Préférezisna(), adapté aux marqueurs reconnus par pandas. - Supprimer des lignes ayant quelques valeurs communes. Une comparaison partielle ne prouve pas l’identité des observations.
- Présenter une valeur imputée comme si elle avait été retrouvée. Conservez la règle et, si utile, un indicateur d’absence.
- Exécuter une cellule avant son chargement. Une erreur
NameErrorsurdfsignifie ici que la cellule de lecture doit être exécutée dans la session en cours.
À retenir et poursuivre le parcours
Le diagnostic précède la transformation : compter les valeurs manquantes, distinguer les cellules des observations, puis justifier chaque suppression ou chaque remplacement. Un doublon exact concerne une ligne entière. Un identifiant en double est examiné conformément à la règle d’unicité attendue. Les résultats du classeur sont précis : 235 absences sur 229 lignes, trois variables catégorielles concernées et aucun doublon exact dans les deux vues étudiées.
Sources et documentation
- Jake VanderPlas, Python Data Science Handbook, 2e édition, version Early Release, chapitre 3 « Data Manipulation with Pandas », section « Handling Missing Data ». Cette section présente les marqueurs d’absence et les opérations de détection, de suppression et de remplacement. Une présentation de ces notions est accessible sur le site de l’auteur.
- Aurélien Géron, Hands-On Machine Learning with Scikit-Learn and PyTorch, 2025, chapitre 2 « End-to-End Machine Learning Project », section « Clean the Data », p. 70–71. Le passage distingue le retrait de lignes, le retrait d’une variable et l’imputation ; les valeurs de remplacement sont apprises sur les données d’entraînement puis réutilisées sur les autres jeux. Les notebooks qui accompagnent le livre sont disponibles sur le dépôt de l’auteur.
Les sorties ont été exécutées avec Python 3.14.8, pandas 3.0.6 et openpyxl 3.1.5 sur le classeur proposé. Les méthodes utilisées sont décrites dans les références liées au fil du texte. Pour approfondir : représentation des données manquantes dans pandas, stratégies d’imputation dans scikit-learn et prévention des fuites de données. La page du jeu Student Performance Factors fournit sa description et sa licence.