Dans ce devoir, nous allons classer des échantillons de roches issus d’un levé régional de géochimie sur roche totale. Le levé contient 10 000 échantillons. Pour chaque échantillon, un laboratoire a mesuré les concentrations des oxydes d’éléments majeurs (en pourcentage massique), la masse volumique apparente et la susceptibilité magnétique. Des géologues de terrain ont cartographié chaque site d’échantillonnage et attribué une étiquette de lithologie : granite, basalte ou andésite. Les classes sont déséquilibrées.
Le tableau est engendré par le paquet du cours mlgeo_synth avec une graine fixée ; l’enseignante conserve une variante à graine cachée, utilisée pour vérifier par sondage les résultats rendus.
Dans ce devoir, nous entraînerons plusieurs classifieurs à prédire la classe d’un échantillon de roche à partir des mesures (caractéristiques). Nous nous exercerons à la préparation des données, à la réduction de dimension, à la conception et à l’entraînement de modèles, à la comparaison de modèles et à la sélection par importance des caractéristiques.
Importation des bibliothèques¶
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
1. Préparation des données (20 points)¶
Nous suivons les étapes suivantes :
- lecture (1 point)
- nettoyage (3 points)
- corrélations (4 points)
- exploration, dispersion des valeurs (3 points)
- réduction de dimension (9 points)
import mlgeo_synth
geo = mlgeo_synth.geochem_table(n=10000, seed=2026)
geo.insert(0, "sample_id", [f"S{i:05d}" for i in range(len(geo))])
geo.to_csv("rock_survey.csv", index=False)1.1 Lecture des données¶
Lisez le tableau pandas depuis le fichier csv « rock_survey.csv ».
Tâche : lire le tableau pandas (1 point)
Gardez une copie du tableau, au cas où.
Description des champs de données
- sample_id = identifiant de l’échantillon, sans mystère.
Les oxydes d’éléments majeurs, rapportés en pourcentage massique (wt%) de la roche totale :
- SIO2 = silice (SiO2), l’oxyde principal de la plupart des roches crustales ; élevée dans les roches felsiques comme le granite, faible dans les roches mafiques comme le basalte.
- AL2O3 = alumine (Al2O3), portée principalement par les feldspaths.
- FEO = fer total rapporté en FeO ; élevé dans les roches mafiques.
- MGO = magnésie (MgO), portée par l’olivine et le pyroxène ; élevée dans les roches mafiques.
- CAO = chaux (CaO), portée par le plagioclase calcique et le pyroxène.
- NA2O = soude (Na2O), portée par le plagioclase sodique.
- K2O = potasse (K2O), portée par le feldspath alcalin et les micas ; élevée dans le granite.
Les oxydes sont soumis à la fermeture compositionnelle : leur somme vaut environ 100 wt%, si bien que lorsque l’un augmente, les autres doivent diminuer.
Les propriétés physiques :
density_g_cm3 = masse volumique apparente de l’échantillon en g/cm3.
mag_susc_si = susceptibilité magnétique, en unités SI volumiques ; sensible à la teneur en magnétite de la roche.
label = lithologie cartographiée par les géologues de terrain (granite, basalte ou andésite). Ce sera la variable réponse que nous chercherons à prédire.
1.2 Nettoyage des données¶
Statistiques de base sur notre jeu de données.
Tâche : donnez les informations de base sur les premières lignes (head()) du tableau pandas (0,5 point)
Tâche : trouvez les types de données de la base (flottants, chaînes de caractères, etc.) à l’aide de la fonction info() (0,5 point).
Y a-t-il une caractéristique évidente (ou un élément du tableau) qui ne devrait pas influencer notre prédiction ?
sample_id n’est qu’un identifiant permettant de retrouver les lignes à l’époque où elles étaient stockées dans la base d’origine du levé. Nous n’en aurons donc pas besoin pour la classification, puisqu’il n’est pas lié au résultat.
Tâche : supprimez cette colonne du tableau pandas. (1 point)
Déterminez le nombre d’exemples, le nombre d’attributs ou de caractéristiques, et le type de classe.
Tâche : combien d’objets y a-t-il dans chaque classe ? (1 point)
Les classes sont « granite », « basalte » et « andésite ». Elles sont définies comme des chaînes de caractères, mais nous les convertirons en entiers afin de pouvoir appliquer une fonction de perte aux étiquettes de classe pendant l’entraînement. Pour cela, nous utilisons la fonction sklearn.preprocessing.LabelEncoder(). Nous allons donc modifier les classes dans le tableau. Il vaut mieux garder une copie du tableau d’origine, par sécurité.
1.3 Corrélations entre données¶
Cherchons maintenant les corrélations les plus élémentaires entre caractéristiques. Cela se fait avec la fonction corr() appliquée au tableau pandas. Évaluez cette fonction et commentez quelles caractéristiques sont corrélées entre elles. Il est commode d’utiliser la fonction matplotlib matshow() pour la clarté. seaborn est un module python qui produit de très jolis graphiques statistiques : https://
Tâche : tracez la matrice de corrélation, appelable depuis le tableau pandas. (2 points)
Indications :
Utilisez les fonctions de heatmap et ajoutez les étiquettes sur les axes. La palette coolwarm convient bien aux échelles divergentes comme les corrélations, qui varient entre -1 et 1. L’argument center=0 garantit que la palette diverge à partir de zéro. Veillez à ignorer la colonne d’étiquettes « label ». Rappelez-vous qu’une colonne peut être supprimée sur place : rock_df.drop('label', axis=1).
Tâche : reproduisez le même graphique pour chacune des trois classes. (1 point) Vous pouvez sélectionner les valeurs du tableau pandas en filtrant sur la colonne « label ».
Tâche : pouvez-vous commenter les groupes de caractéristiques corrélées entre elles ou qui semblent indépendantes les unes des autres au vu de ces corrélations ? (1 point) Attendez-vous à de fortes corrélations entre les oxydes : la fermeture compositionnelle les force à se compenser mutuellement, et la différenciation magmatique les entraîne ensemble. La masse volumique et la susceptibilité magnétique sont-elles corrélées aux oxydes ? Les motifs diffèrent-ils entre les trois lithologies ?
1.5 Exploration des données¶
Étant donné la structure des corrélations, nous allons explorer les valeurs des données.
1.5.a. Distributions de SiO2¶
La teneur en silice est le premier nombre que regarde un pétrologue : elle augmente avec la différenciation magmatique et sépare les roches felsiques des roches mafiques.
Tâche : tracez des histogrammes de la colonne de caractéristique ‘SIO2’ pour chaque classe (1 point).
Tâche : décrivez brièvement la différence entre les trois histogrammes. (0,5 point)
Granite :
Basalte :
Andésite :
1.5.b. Masse volumique et susceptibilité magnétique¶
Nous allons maintenant tracer la masse volumique apparente (density_g_cm3) en fonction de la susceptibilité magnétique (mag_susc_si), colorée par classe. Vous pouvez utiliser la fonction scatterplot ou lmplot de seaborn (https://
Tâche : voyez-vous des différences évidentes qui permettraient de discriminer facilement les classes ? (0,5 point)
1.5.c Les oxydes majeurs¶
Rappel : la matrice de corrélation montre que les oxydes d’éléments majeurs sont corrélés entre eux pour les trois classes.
Tâche : tracez les histogrammes des autres oxydes (AL2O3, FEO, MGO, CAO) et expliquez pourquoi vous vous attendez à ce que ces caractéristiques soient corrélées (1 point)
1.6 Réduction de dimension des données¶
À ce stade, il nous reste 9 caractéristiques : les sept oxydes (SIO2, AL2O3, FEO, MGO, CAO, NA2O, K2O), density_g_cm3 et mag_susc_si. Parmi elles, les oxydes sont corrélés entre eux. Il y a donc une possibilité de réduire la dimension des caractéristiques par une ACP (PCA) sur ces 7 caractéristiques.
Nous utiliserons la fonction sklearn sklearn.decomposition.PCA() pour ajuster les données et les transformer dans les coordonnées des composantes principales (CP). Explorons d’abord le nombre de CP nécessaires. Ajustez la fonction PCA sur le nombre total d’oxydes. Vous ajusterez la fonction PCA sur un tableau formé des colonnes sélectionnées dans le tableau de données.
Tâche : effectuez l’ACP sur un nombre maximal de CP, affichez les valeurs du rapport de variance expliquée, et décidez d’un nombre maximal de CP approprié (6 points)
Réponse : combien de CP utiliser
Nous allons maintenant refaire l’ACP avec le nombre de CP que vous avez jugé le plus approprié. Réappliquez la fonction fit-transform. Mettez à jour le tableau en y ajoutant la ou les valeurs d’ACP et en supprimant les colonnes des 7 caractéristiques d’oxydes.
Tâche : refaites l’ACP, ajustez et transformez, mettez à jour le tableau avec la ou les nouvelles caractéristiques (3 points)
2. Partitionnement non supervisé avec KMeans (20 points)¶
Dans cette section, nous explorerons si les caractéristiques des données suffiront à la classification. Comme première exploration, nous effectuerons une classification non supervisée par partitionnement (clustering) KMeans.
2.1 Réaliser un KMeans préliminaire (10 points)¶
Mettez en œuvre KMeans ici pour un nombre de groupes donné et sur les caractéristiques d’intérêt. Choisissez 3 caractéristiques (par exemple PC1, density_g_cm3 et mag_susc_si ; n’oubliez pas de les mettre à l’échelle).
- Utilisez
sklearnpour réaliser le KMeans. - Répétez le KMeans et discutez (dans une cellule markdown) la stabilité du partitionnement (par exemple, servez-vous d’une visualisation pour l’évaluer qualitativement).
2.2 Trouver le nombre optimal de groupes (5 points)¶
Utilisez une méthode pour établir le nombre optimal de groupes.
2.3 Discuter la performance du partitionnement (5 points)¶
- Réalisez une analyse de silhouette (visualisation et score de silhouette)
- Calculez (cellule python) et discutez (dans une cellule markdown distincte) l’homogénéité par rapport aux étiquettes de vérité terrain, à l’aide de 3 métriques appropriées.
Question : Après avoir réalisé le partitionnement KMeans et calculé les scores de complétude, d’homogénéité et de Fowlkes-Mallows, comment déterminer si ces scores sont bons ? Comparez les scores obtenus aux valeurs idéales et expliquez ce que chaque score indique sur la qualité du partitionnement. Que concluez-vous de vos résultats ?
3 Modèles d’apprentissage automatique (30 points)¶
Nous allons maintenant entraîner différents modèles sur ce jeu de données. Nous disposons des caractéristiques qui subsistent après réduction de dimension, de 3 classes et de 10 000 échantillons. Nous utiliserons les K plus proches voisins, le bayésien naïf, la forêt aléatoire, la machine à vecteurs de support et le gradient boosting (renforcement par gradient) à histogrammes.
Nous suivons maintenant un flux de travail d’apprentissage automatique classique :
- Mise à l’échelle des caractéristiques (3 points)
- Découpage entraînement/test (2 points)
- Conception, entraînement et test des modèles (15 points)
- Comparaison des modèles, choix du vainqueur, discussion de l’importance des caractéristiques à l’aide de la forêt aléatoire. (10 points)
3.1 Mise à l’échelle des caractéristiques¶
Ramener toutes les valeurs dans l’intervalle (0, 1) réduira la distorsion due aux valeurs exceptionnellement élevées et fera converger plus vite certains algorithmes. Vous pouvez mettre à l’échelle les seules caractéristiques en supprimant la colonne « label » sans modifier le tableau sur place, à l’aide de la fonction pandas drop().
Tâche : mettez à l’échelle uniquement les caractéristiques (3 points)
3.2 Ensembles de test, d’entraînement et de validation¶
Tâche : découpez les données en une partie d’entraînement et une partie de test. (2 points)
Les modèles seront entraînés sur l’ensemble d’entraînement et testés sur l’ensemble de test. Utilisez un découpage stratifié (stratify=y) — les classes sont déséquilibrées.
Le temps de calcul est important à prendre en compte lorsque le jeu de données et la taille du modèle augmentent. Vous pouvez évaluer le temps de calcul relatif à l’aide de la fonction time.perf_counter(), qui donne le temps absolu. Comparez ensuite les temps de calcul en faisant la différence entre deux horodatages :
t1=time.perf_counter()
t2=time.perf_counter()
tcomp = t2 - t1
Nous évaluerons également la performance de ces classifieurs multi-classes. Nous évaluerons la moyenne des scores sur les 3 étiquettes de classe.
Dans ce qui suit, nous testerons plusieurs classifieurs. Suivez les étapes :
- définition/conception du modèle
- entraînement
- prédiction sur le test
- évaluation : a) afficher le classification_report ; b) sauvegarder la précision, le rappel, le score F et l’exactitude dans des variables
3.3.a K plus proches voisins (3 points)¶
Consultez les arguments et la définition de la fonction ici : https://
3.3.b Bayésien naïf (3 points)¶
Consultez les pages du tutoriel sklearn ici : https://
Le bayésien naïf suppose que les données suivent une loi normale, ce que l’on peut approcher par une mise à l’échelle avec le MaxAbsScaler. Pour cet exemple, nous partirons donc des données non mises à l’échelle, puis nous les remettrons à l’échelle.
3.3.c Classifieur par forêt aléatoire (3 points)¶
Consultez la page du tutoriel ici : https://
3.3.d Classifieur à machine à vecteurs de support (3 points)¶
Consultez la page d’information sklearn ici : https://
3.3.e Gradient boosting à histogrammes (3 points)¶
Consultez la page d’information ici : https://
3.4 Performance et comparaison des modèles¶
3.4.a Matrice de confusion et interprétation¶
Tâche : tracez la matrice de confusion (2 points)
Utilisez ConfusionMatrixDisplay de sklearn pour visualiser la matrice de confusion
Tâche : commentez quel est, selon vous, le meilleur classifieur (1 point). Vous pouvez aussi commenter les taux d’erreur de classification et de confusion.
3.4.b Validation croisée à K plis¶
Nous allons maintenant effectuer une validation croisée à K plis pour les classifieurs. Nous utilisons la fonction cross_val_score sur chaque estimateur, sur l’ensemble d’entraînement, avec 10 plis stratifiés (StratifiedKFold(n_splits=10)), et le F1 macro comme métrique de score (scoring="f1_macro") — les classes sont déséquilibrées, donc l’exactitude récompenserait le fait d’ignorer la classe rare.
Tâche : effectuez la validation croisée sur K plis, affichez la moyenne et l’écart-type du score F1 macro (3 points)
Tâche : quelle méthode a remporté le test de validation croisée (1 point) ?
voir la cellule ci-dessous
3.4.c Et le vainqueur est...¶
Comparons les résultats. Tâche : créez un tableau pandas rassemblant toutes les métriques de performance, y compris les résultats de la validation croisée à K plis. (2 points)
Tâche : commentez les scores F1 macro et la performance, et choisissez un vainqueur. (1 point)
voir la cellule ci-dessous
4 Synthèse (4 points)¶
4.1 Importance des caractéristiques à l’aide du classifieur par forêt aléatoire¶
Les arbres de décision ont la propriété singulière de pouvoir ordonner les caractéristiques selon leur capacité à séparer les classes. Si certaines caractéristiques dominent les autres dans le pouvoir prédictif des classes, on peut réduire davantage la dimension des caractéristiques pour des analyses supplémentaires. Le vecteur d’importance des caractéristiques est le module rfc.feature_importances_, trié par importance croissante. Stockez le vecteur d’importance.
Rappelez-vous la mise en garde de la leçon 3.7 : l’importance n’est pas la causalité. Le classement indique ce que le modèle utilise pour prédire, non ce qui fait qu’une roche est un granite — et les importances par impureté répartissent le mérite entre caractéristiques corrélées, y compris les CP que vous avez construites à partir des oxydes.
Tâche : tracez un diagramme en barres à l’aide de la fonction matplotlib.pyplot.bar. (2 points)
Tâche : quelles sont les trois caractéristiques les plus importantes (1 point) ?
répondez dans la cellule ci-dessous
Dans ce carnet, vous avez probablement constaté que les caractéristiques liées à la différenciation (la première CP des oxydes, la masse volumique, la susceptibilité magnétique) séparent les lithologies. Un pétrologue vous aurait dit que la teneur en silice sépare le granite du basalte — mais vous savez désormais quantifier à quel point, et ce que coûte l’automatisation.
Tâche : commentez brièvement ce que vous avez appris (1 point)
voir la cellule ci-dessous