Skip to content
Snippets Groups Projects

Typo

Merged Ghost User requested to merge develop into main
2 files
+ 2
2
Compare changes
  • Side-by-side
  • Inline
Files
2
%% Cell type:markdown id:e3d7f78f-21f2-474b-97c2-1fcfabd272cc tags:
# Ajuster son premier modèle prédictif
%% Cell type:markdown id:efd00c69-212a-4c57-8f5c-f0e9724bf8bd tags:
Au cours de ce TD, vous serez amené·e à ajuster un modèle simple (et peu performant) pour prédire l’appartenance de tel ou tel manchot à une espèce pré-définie : manchot Adélie, manchot papou (*Gentoo*) ou manchot à jugulaire (*Chinstrap*). Vous mettrez pour cela en œuvre un algorithme d’apprentissage supervisé appelé *k-nearest neighbors* (k-NN) qui effectuera une comparaison entre les données envoyées pour la prédiction et les *k* observations les plus proches dans le jeu d’entraînement.
La première tentative se révélera peu concluante, puis vous améliorerez progressivement la performance de votre algorithme en travaillant sur les données d’entraînement.
%% Cell type:markdown id:b7b7ee43-1900-4bbd-a984-a03dfeaea81e tags:
## À propos du jeu de données
%% Cell type:markdown id:ad5a468a-bf49-4259-8488-5eb288235ca5 tags:
![Meet the palmer penguins](../images/penguins.png)
Artwork by @allison_horst
Le fichier [*penguin-census.csv*](../files/penguin-census.csv) (Gorman, 2014) provient du paquet [*palmerpenguins*](https://allisonhorst.github.io/palmerpenguins/) conçu pour le logiciel *R* comme un outil pour l’exploration et la visualisation de données. Il contient deux jeux de données : un avec les données complètes et un autre qui se veut comme une version simplifiée du premier. C’est ce dernier que vous utiliserez.
Les données ont été collectées par le Dr. Kristen Gorman à la station Palmer en Antarctique.
%% Cell type:markdown id:5c537b69-f8ce-4cef-8e38-6760c862f565 tags:
## Description des données
%% Cell type:markdown id:41e3b57a-7b3f-461d-81ca-e58ff12cb255 tags:
On n’insistera jamais assez sur l’influence d’une bonne compréhension des données à disposition sur la qualité de l’algorithme produit. Si vous avez l’impression de perdre du temps à explorer manuellement les fichiers ou à lire la documentation, rappelez-vous Hume : l’impression ne peut être représentative en ce qu’elle se présente immédiatement à l’esprit. L’idée qui en dérive, si elle a moins de force ou de vivacité, peut en revanche servir pour, en réaction, modifier l’impression primitive. En somme, non, vous ne perdez pas de temps.
Les données sont constituées de 344 observations (*samples*) décrites par 8 variables aléatoires, ou caractéristiques (*features*). Ces variables sont :
|Variable|Signification|Type de variable|
|-|-|:-:|
|*species*|Espèce de manchot parmi : Adelie, Gentoo, Chinstrap|qualitative|
|*island*|Île de l’observation parmi : Torgersen, Biscoe, Dream|qualitative|
|*bill_length_mm*|Longueur du bec de l’individu (en mm)|quantitative discrète|
|*bill_depth_mm*|Épaisseur du bec de l’individu (en mm)|quantitative discrète|
|*flipper_length_mm*|Longueur de la nageoire de l’individu (en mm)|quantitative discrète|
|*body_mass_g*|Poids de l’individu (en g)|quantitative discrète|
|*sex*|Sexe de l’individu selon deux valeurs possibles : *male* ou *female*|qualitative binaire|
|*year*|Année de l’observation (de 2007 à 2009)|qualitative ordonnée|
%% Cell type:markdown id:995bae5a-201b-44fa-8eb9-8ba0bd8c1c33 tags:
### Définition de la tâche
%% Cell type:markdown id:61fe45f8-f274-446e-b29e-0143d85cdd29 tags:
L’objectif de votre programme est de concevoir une fonction qui détermine si un individu appartient à telle ou telle espèce de manchot. Comme vous ne savez pas encore comment traiter des données catégorielles (sexe, profession, statut, pour ou contre…), vous limiterez les données d’entraînement aux variables quantitatives.
**Variable cible (*target*) :** *species*
**Caractéristiques (*features*) :** *bill_length_mm*, *bill_depth_mm*, *flipper_length_mm*, *body_mass_g*
%% Cell type:markdown id:eec6c135-5262-4e9c-884c-b877901b20ee tags:
## Un coup d’œil rapide aux données
%% Cell type:markdown id:56b3a9fb-4182-47fb-bfdd-33b159804c91 tags:
### Chargement du fichier
%% Cell type:markdown id:4723cd0d-9d06-48b2-b34b-45e60ea55c60 tags:
Importez tout d’abord le fichier *penguin-census.csv*, situé dans le répertoire *files*, grâce à la méthode `.read_csv()` de la librairie *Pandas* :
%% Cell type:code id:15db0e54-9244-4a63-a3ab-25d5b2826dc8 tags:
``` python
# your code here
# load pandas library
import pandas as pd
# load the census
penguin_census = pd.read_csv("../files/penguin-census.csv")
```
%% Cell type:markdown id:b4d79062-0c0b-4cd9-8074-d992851f573c tags:
### Exploration des données
%% Cell type:markdown id:bd51ffd7-6e83-4347-91de-d2b8b24ada7c tags:
Avant toute chose, confirmez le nombre d’individus qui constituent le jeu de données :
%% Cell type:code id:4f61da20-08d1-415b-8a97-15414d20255a tags:
``` python
# your code here
# number of samples
len(penguin_census)
```
%% Cell type:markdown id:a0482e7e-cf41-4428-8822-a01171b6b15e tags:
La méthode `.head()` permet d’obtenir un aperçu des premières observations. Utilisez-là sur la variable dans laquelle vous avez chargé le *data frame* :
La méthode `.head()` permet d’obtenir un aperçu des premières observations. Utilisez-la sur la variable dans laquelle vous avez chargé le *data frame* :
%% Cell type:code id:30a56431-c889-49e2-ba12-df658601643c tags:
``` python
# your code here
# look at the data
penguin_census.head()
```
%% Cell type:markdown id:40bde9d5-b192-4409-9a9f-c97a9d6c7a11 tags:
Une propriété intéressante des *data frames* est `dtypes`, qui fournit le type de donnée de chaque variable :
%% Cell type:code id:569db929-625e-4e72-a36f-06d1173a5310 tags:
``` python
# your code here
# data types
penguin_census.dtypes
```
%% Cell type:markdown id:2672ec64-f918-487c-a931-0bfc613381aa tags:
Utilisez à présent la méthode `.describe()` pour obtenir des mesures statistiques sur les variables quantitatives :
%% Cell type:code id:d1127f6e-5126-441e-a6a5-c5dd11fe946b tags:
``` python
# your code here
# some statistic measures on quantitative features
penguin_census.describe()
```
%% Cell type:markdown id:b453590f-2f1e-4ecd-88f1-87f5c3212f84 tags:
### À la recherche des données manquantes
%% Cell type:markdown id:0db57d9e-d4ac-49bd-a67a-8875fa4cc881 tags:
Plus haut, dès l’utilisation de la méthode `.head()`, vous avez révélé l’absence de certaines données. L’information est confirmée par la méthode `.describe()` qui ne totalise que 342 observations valides pour les variables *bill_length_mm*, *bill_depth_mm*, *flipper_length_mm* et *body_mass_g* sur les 344 individus.
Une façon plus sûre de les détecter est d’utiliser la méthode `.isnull()` :
%% Cell type:code id:5526e94c-f250-4cdb-ae8c-e3a3b425789b tags:
``` python
# your code here
# which values are null in the dataset?
penguin_census.isnull()
```
%% Cell type:markdown id:67740122-5a47-41c9-990c-f39f0dc83d8c tags:
Mieux encore, chaînez l’opération précédente avec la méthode `.any()` pour déterminer dans quelles colonnes on trouve des données manquantes :
%% Cell type:code id:3706f753-0347-4b10-8908-cd05e9513a30 tags:
``` python
# your code here
# in which columns are the missing values?
penguin_census.isnull().any()
```
%% Cell type:markdown id:ad39dce1-09c7-4de2-b5ec-ceee8957c8fa tags:
Vous pouvez maintenant pister, colonne par colonne, les données manquantes. La syntaxe se construit de la manière suivante :
1. Appliquez un prédicat à votre *data frame*
`df[]` ;
2. dans le prédicat, limitez la sélection à la colonne appropriée
`df[df[col]]` ;
3. révélez les valeurs manquantes de la colonne sélectionnée avec `.isnull()`
`df[df[col].isnull()]` ;
4. ne retenez que les indices des observations sélectionnées (en dehors du prédicat) avec la propriété `index`
`df[df[col].isnull()].index` ;
5. transformez enfin le tout en liste avec la méthode `.to_list()`
`df[df[col].isnull()].index.to_list()`.
%% Cell type:code id:5b3e09c4-f6ab-4ed1-aea6-5733b5d6cbef tags:
``` python
# your code here
# where are precisely the missing values?
[
f"{col} : {penguin_census[penguin_census[col].isnull()].index.to_list()}"
for col in ['bill_length_mm', 'bill_depth_mm', 'flipper_length_mm', 'body_mass_g', 'sex']
]
```
%% Cell type:markdown id:0cbde3c3-4240-41a4-841a-9b2ed27e41bb tags:
### Visualiser les données
%% Cell type:markdown id:c73d4fda-500e-4cbb-97e2-1acd658832d7 tags:
La librairie *Pandas* embarque des outils hérités de *Matplotlib*. La méthode `.hist()` est toute indiquée pour représenter des variables numériques. Notez qu’il n’est pas nécessaire d’opérer colonne par colonne. *Pandas* n’applique la méthode que sur des variables de type numérique :
%% Cell type:code id:be8f5437-73fd-4abe-a774-653e5e11f852 tags:
``` python
# your code here
_ = penguin_census.hist(figsize=(8,8))
```
%% Cell type:markdown id:51b75fff-8782-4f1a-844d-3265c89b4f28 tags:
Mieux encore, la librairie *Seaborn* offre des outils qui facilitent davantage la lecture des graphiques. Importez tout d’abord le module `seaborn` avec l’alias `sn`, puis utilisez la méthode `.pairplot()` en lui passant deux paramètres : votre *data frame* et le nom de la variable cible (paramètre nommé `hue`) :
%% Cell type:code id:8656581d-5764-4283-86e9-de8f34f77e90 tags:
``` python
# your code here
# module seaborn
import seaborn as sn
# combination of plots
_ = sn.pairplot(penguin_census, hue="species")
```
%% Cell type:markdown id:7201f7af-bf94-43a0-b72b-ad6e29f43846 tags:
## Préparez le jeu de données
%% Cell type:markdown id:c82c0a6b-a097-4b82-8e24-42191a898e17 tags:
Après avoir consacré un temps non négligeable à la compréhension du jeu de données, il est temps de le préparer afin de fournir un *data frame* propre à votre futur programme.
Commencez par définir la colonne cible dans une variable *target* et par faire la liste des caractéristiques qui vous intéressent dans une variable *features* :
%% Cell type:code id:ddf31392-ffef-4d02-a96b-7925d6b061bf tags:
``` python
# your code here
target = "species"
features = ["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"]
```
%% Cell type:markdown id:767c28ea-8b23-4bf5-925e-f7db03b6f908 tags:
Le nouveau *data frame* correspondra à la réunion des seules colonnes répertoriées dans vos variables *target* et *features*. Par convention, on positionne la colonne cible à la fin :
%% Cell type:code id:740b56d1-9960-4404-908a-b32fcdbebb37 tags:
``` python
# your code here
# a new data frame
data = pd.DataFrame(penguin_census[features + [target]])
```
%% Cell type:markdown id:848417aa-f7c2-484e-bf1b-16bb9b7dc041 tags:
Lorsque vous avez fait la chasse aux données manquantes dans le fichier, vous avez sans doute remarqué que :
- les colonnes qui vous intéressent ne contenaient que deux données manquantes ;
- ces données concernent les deux mêmes individus.
Vous pouvez de manière légitime considérer que supprimer totalement ces deux individus ne nuira pas à votre programme. Appliquez la méthode `.dropna()` directement sur le *data frame* :
%% Cell type:code id:98bb8930-08ea-4169-b2be-0cc1de6c0f7e tags:
``` python
# your code here
data.dropna(inplace=True)
```
%% Cell type:markdown id:f40dfcc4-8f13-4cdd-9d89-25b50199741c tags:
Votre *data frame* n’est plus constitué que de 342 observations. Il est temps de le séparer en deux autres structures :
1. une série nommée `y` pour la cible ;
2. un *data frame* nommé `X` pour les caractéristiques (sans la colonne cible).
La méthode `.drop()` avec l'argument nommé `columns` permet de spécifier une liste de colonnes à supprimer.
%% Cell type:code id:6935e3ff-4d6e-4219-b784-3b20e5c6722b tags:
``` python
# your code here
y = data[target]
X = data.drop(columns=[target])
```
%% Cell type:markdown id:25dc82a1-9fdd-477a-950b-99fb8365d448 tags:
## Constituez les jeux d’entraînement et de test
%% Cell type:markdown id:ded560bd-a9b9-4a41-b5c1-31557cf78a69 tags:
Durant cette étape, vous allez séparer vos structures `X` et `y` en deux parties : la première pour l’entraînement, la seconde pour le test.
Comptabilisez dans une variable `nb` le nombre d’observations et définissez une variable `limit` qui soit 25 % de `nb`. Assurez-vous que `limit` soit un entier :
%% Cell type:code id:429f1536-ac2f-4316-820b-e0927966b7ad tags:
``` python
# your code here
nb = len(X)
limit = int(nb * 0.25)
```
%% Cell type:markdown id:f8de7405-11b2-45f7-aafb-494814c8029b tags:
Grâce au *slicing*, effectuez la séparation entre `X_train`, `X_test` et `y_train`, `y_test` :
%% Cell type:code id:4f589678-8487-4a74-8e76-94824661f84c tags:
``` python
# your code here
# split train/test
X_train = X[limit:]
X_test = X[:limit]
y_train = y[limit:]
y_test = y[:limit]
```
%% Cell type:markdown id:2ae12b1d-1c22-4ea6-a309-efc5ceb4e11d tags:
## Programmation du modèle
%% Cell type:markdown id:e3993406-e8a6-45ba-9e0b-ea2da75d41cc tags:
### Entraîner le modèle avec le jeu d’entraînement
%% Cell type:markdown id:9e03b55f-ceb1-4a76-8f70-6990f61cf43d tags:
La partie qui aurait pu sembler la plus complexe est en fait la plus triviale. *Scikit-Learn* se charge de calculer l’ensemble des paramètres et fournit un modèle selon l’algorithme d’entraînement utilisé.
Importez tout d’abord la classe `KNeighborsClassifier` du module `sklearn.neighbors` :
%% Cell type:code id:1b696f57-9654-4986-839e-1a175d6fb954 tags:
``` python
# your code here
from sklearn.neighbors import KNeighborsClassifier
```
%% Cell type:markdown id:a9e996a3-6cd3-467d-941a-ce158ed662a8 tags:
Chargez à présent la classe `KNeighborsClassifier()` dans une variable `model` puis appelez directement la méthode `.fit()` en lui passant en paramètres `X_train` puis `y_train` :
%% Cell type:code id:76c68b94-9c3b-463b-8e86-fc5e248f25ed tags:
``` python
# your code here
model = KNeighborsClassifier()
_ = model.fit(X_train, y_train)
```
%% Cell type:markdown id:5f309273-5768-4167-8777-796d1d080621 tags:
### Tester le modèle
%% Cell type:markdown id:b9c83ba4-283b-4767-9eb2-9f43d3a53c6b tags:
Il ne reste plus qu’à effectuer des prédictions sur les données de test avec la méthode `.predict()` :
%% Cell type:code id:e467e4f0-dfa8-4a7f-a1fb-936033442104 tags:
``` python
# your code here
y_predicted = model.predict(X_test)
```
%% Cell type:markdown id:4533c45f-bdb5-4390-babc-aa85cefb7a07 tags:
### Évaluer le modèle
%% Cell type:markdown id:3faa3ec2-5340-45f3-88c8-c7ea3af40e91 tags:
Pour évaluer l’exactitude du modèle, il suffit de comparer les prédictions obtenues sur le jeu de test avec le contenu de `y_test`, puis de noter les concordances. L’opérateur d’égalité `==` permet de vérifier si les observations d’une série correspondent avec celles d’une autre :
%% Cell type:code id:a8c9e8b4-56eb-41cd-bc37-d00889f4c53a tags:
``` python
# your code here
y_predicted == y_test
```
%% Cell type:markdown id:10d4ac41-c475-404e-8270-b2644507f591 tags:
Le résultat obtenu étant une série de booléens, il est possible d’appeler les méthodes `.sum()` ou `.mean()` pour obtenir le nombre de bonnes prédictions rapportées au nombre total d’éléments :
%% Cell type:code id:4cac7f52-910a-4efd-a3b6-db7f82dfe9f9 tags:
``` python
# your code here
(y_predicted == y_test).mean()
```
%% Cell type:markdown id:4d6e3793-026a-40c5-80c9-968a1004b1e0 tags:
Mieux, la méthode `.score()` du modèle entraîné permet de révéler le résultat immédiatement. Passez simplement en paramètres le jeu de test et la cible de test :
%% Cell type:code id:36379e25-b98f-4060-82c5-ab67638221d1 tags:
``` python
# your code here
model.score(X_test, y_test)
```
%% Cell type:markdown id:56fc1ab5-32a3-426c-bb33-e49d6f30d319 tags:
### Améliorer le modèle
%% Cell type:markdown id:051d0840-abc9-4416-9406-9edbca0081e3 tags:
**49 % de taux d’exactitude !!** Même pas une prédiction sur deux de juste, autant dire que votre premier modèle est ridiculement inefficace…
La première voie d’amélioration réside dans la préparation du jeu de données. Remarquez que vos données sont triées par espèces de manchots. Si vous ressortez les données uniques de `y_test`, vous remarquez alors qu’il n’y a que des manchots Adélie :
%% Cell type:code id:948c3ec2-e58f-4a72-a898-43912fdc9ab1 tags:
``` python
# unique values in y_test
y_test.unique()
```
%% Cell type:markdown id:6b89a2a1-58a7-4516-9197-fe4e7bd26c4f tags:
Alors que dans la série cible d’entraînement les manchots papous sont sur-représentés :
%% Cell type:code id:9237957f-a5b5-4505-8c9b-d65313ac8370 tags:
``` python
# nb of samples for each class in y_train
y_train.value_counts()
```
%% Cell type:markdown id:392864dc-b493-4621-bf1c-86e195a14346 tags:
La librairie *Pandas* met à disposition une méthode `.sample()` qui permet de mélanger les observations :
%% Cell type:code id:6dcf0fba-8b2b-4391-9f0f-e0ffdeb31b0e tags:
``` python
# shuffle all rows
data = data.sample(frac=1).reset_index(drop=True)
```
%% Cell type:markdown id:334d1a65-ebec-4e4e-9a62-9096efcec496 tags:
Séparez à nouveau votre *data frame* en `X` et `y`, puis en jeux de test et d’entraînement, et entraînez le modèle tel quel. Vous devriez noter une hausse non négigeable du taux d’exactitude !
Notez qu’il existe une fonction dans *Scikit-Learn* pour préparer automatiquement les données de test et d’entraînement :
%% Cell type:code id:377d211a-1088-409c-9714-4ae4d22e1ba9 tags:
``` python
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=0.25)
```
%% Cell type:markdown id:4c589cde-b1d5-4f37-b66a-3dc370205762 tags:
N’hésitez pas à tester d’autres pistes d’amélioration, vous ne devriez pas tarder à dépasser les 80 % d’exactitude :
- Modifier le paramètre `random_state` de la fonction `train_test_split()` ;
- augmenter le nombre d’observations dans le jeu d’entraînement (ex. : 80/20) ;
- ajuster le paramètre `n_neighbors` de la classe `KNeighborsClassifier()` (5 par défaut) ;
-
%% Cell type:markdown id:2b003848-202f-4088-b5bf-a9691393ecf1 tags:
## Phase IV
%% Cell type:markdown id:388fdff3-ce87-496a-b8c0-aa7dbb411cd6 tags:
Il est temps de présenter des données inédites à votre programme et voir de quelle manière il se comporte. Chargez les données ci-dessous :
%% Cell type:code id:2dd9a204-19b6-421d-a4c4-6748969ba004 tags:
``` python
series = {
"bill_length_mm": [54.2, 48.2],
"bill_depth_mm": [19.7, 13.9],
"flipper_length_mm": [200.9, 181.7],
"body_mass_g": [4367, 3659]
}
new_data = pd.DataFrame(series)
```
%% Cell type:markdown id:805eb15f-8002-48cb-9868-923ebddcd202 tags:
À l’aide de la méthode `.predict()`, regardez les étiquettes qui ressortent :
%% Cell type:code id:d4b65193-7d7d-4e41-b102-be4cbd11f541 tags:
``` python
# your code here
model.predict(new_data)
```
Loading