Classificateurs

Dans cette feuille, nous allons explorer l’utilisation de plusieurs classificateurs sur l’exemple des pommes et des bananes. Vous pourrez ensuite les essayer sur votre jeu de données.

Commencons par charger les utilitaires et autres librairies:

import os, re
from glob import glob as ls
import numpy as np                    # Matrix algebra library
import pandas as pd                   # Data table (DataFrame) library
import seaborn as sns; sns.set()      # Graphs and visualization library
from PIL import Image                 # Image processing library
import matplotlib.pyplot as plt       # Library to make graphs 
# Configuration intégration dans Jupyter
%matplotlib inline

## les utilitaires
%load_ext autoreload
%autoreload 2
from utilities import *

## les jeux de données
from intro_science_donnees import data

Chargement et préparation des données

On charge le jeu de données prétraité (attributs rougeur et élongation et classes des fruits), tel que fournis en semaine 3:

df = pd.read_csv("attributs.csv", index_col=0)
# standardisation
dfstd =  (df - df.mean()) / df.std()
dfstd['class'] = df['class']

On partitionne le jeu de données en ensemble de test et d’entraînement:

X = dfstd[['redness', 'elongation']]
Y = dfstd['class']
#partition des images
train_index, test_index = split_data(X, Y, seed=0)

#partition de la table des attributs
Xtrain = X.iloc[train_index]
Xtest = X.iloc[test_index]
#partition de la table des étiquettes
Ytrain = Y.iloc[train_index]
Ytest = Y.iloc[test_index]

Classificateurs basés sur les exemples (examples-based)

Nous allons maintenant voir comment appliquer des classificateurs fournis par la librairie scikit-learn. Commençons par le classificateur plus proche voisin déjà vu en semaines 3 et 4.

KNN : \(k\)-plus proche voisins

from sklearn.neighbors import KNeighborsClassifier

#définition du classificateur, ici on l'appelle classifier
# on choisit k=1
classifier = KNeighborsClassifier(n_neighbors=1)
# on l'ajuste aux données d'entrsainement
classifier.fit(Xtrain, Ytrain) 
# on calcule ensuite le taux d'erreur lors de l'entrainement et pour le test
Ytrain_predicted = classifier.predict(Xtrain)
Ytest_predicted = classifier.predict(Xtest)
# la fonction error_rate devrait etre présente dans votre utilities.py (TP3), sinon ajoutez-la
e_tr = error_rate(Ytrain, Ytrain_predicted)
e_te = error_rate(Ytest, Ytest_predicted)

print("Classificateur: 1 Neighrest Neighbor")
print("Training error:", e_tr)
print("Test error:", e_te)

Exercice : Quels sont les taux d’erreur pour l’ensemble d’entraînement et l’ensemble de test ?

VOTRE RÉPONSE ICI

On mémorise ces taux dans une table error_rates que l’on complétera au fur et à mesure de cette feuille:

error_rates = pd.DataFrame([], columns=['entrainement', 'test'])
error_rates.loc["1 Neighrest Neighbor",:] = [e_tr, e_te]
error_rates

Fenêtres de Parzen (Parzen window ou radius neighbors)

Pour ce classificateur, on ne fixe pas le nombre de voisins mais un rayon \(r\); la classe d’un élément \(e\) est prédite par la classe majoritaire parmi les éléments de l’ensemble d’entraînement dans la sphère de centre \(e\) et de rayon \(r\).

Exercice : Complétez le code ci-dessous:

from sklearn.neighbors import RadiusNeighborsClassifier
classifier = RadiusNeighborsClassifier(radius=1.0)

# on l'ajuste aux données d'entrainement

# YOUR CODE HERE
raise NotImplementedError()

# on calcule ensuite le taux d'erreur lors de l'entrainement et pour le test

# YOUR CODE HERE
raise NotImplementedError()

# on calcule les taux d'erreurs

# YOUR CODE HERE
raise NotImplementedError()

print("Classificateur: Parzen Window")
print("Training error:", e_tr)
print("Test error:", e_te)

Exercice : Complétez la table error_rates avec ce modèle, en rajoutant une ligne d’index Parzen Window.

Indication : Utiliser .loc comme ci-dessus.

# YOUR CODE HERE
raise NotImplementedError()
error_rates
assert isinstance(error_rates, pd.DataFrame)
assert list(error_rates.columns) == ['entrainement', 'test']
assert list(error_rates.index) == ['1 Neighrest Neighbor', 'Parzen Window']
assert (0 <= error_rates).all(axis=None), "Les taux d'erreurs doivent être positifs"
assert (error_rates <= 1).all(axis=None), "Les taux d'erreurs doivent être inférieur à 1"

Exercice \(\clubsuit\) : Faites varier le rayon \(r\). Comment le taux d’erreur varie-t-il ? Vous pouvez ajouter des modèles à la table error_rates s’ils vous semblent pertinents

VOTRE RÉPONSE ICI

Classificateurs basés sur les attributs (feature based)

Régression linéaire

Exercice : Pourquoi ne peut-on pas appliquer la méthode de régression linéaire pour classer nos pommes et nos bananes ?

VOTRE RÉPONSE ICI

Arbres de décision

Les arbres de décison correspondent à des modèles avec des décisions imbriquées où chaque noeud teste une condition sur une variable. Les étiquettes se trouvent aux feuilles.

Exercice : Complétez le code ci-dessous.

from sklearn import tree

classifier = tree.DecisionTreeClassifier()
# on l'ajuste aux données d'entrainement

# YOUR CODE HERE
raise NotImplementedError()

# on calcule ensuite le taux d'erreur lors de l'entrainement et pour le test

# YOUR CODE HERE
raise NotImplementedError()

# on calcule les taux d'erreurs

# YOUR CODE HERE
raise NotImplementedError()


print("Classificateur: Arbre de decision")
print("Training error:", e_tr)
print("Test error:", e_te)

Exercice : Complétez la table error_rates avec ce modèle.

# YOUR CODE HERE
raise NotImplementedError()
print(error_rates)
assert isinstance(error_rates, pd.DataFrame)
assert list(error_rates.columns) == ['entrainement', 'test']
assert error_rates.shape[0] >= 3
assert (0 <= error_rates).all(axis=None), "Les taux d'erreurs doivent être positifs"
assert (error_rates <= 1).all(axis=None), "Les taux d'erreurs doivent être inférieur à 1"

Exercice : Représentez l’arbre de décision comme vu lors du CM5.

import matplotlib.pyplot as plt

plt.figure(figsize=(12,12)) 
# YOUR CODE HERE
raise NotImplementedError()
plt.show()

Exercice : Interprétez cette figure.

VOTRE RÉPONSE ICI

Perceptron

Le perceptron est un réseau de neurones artificiels à une seule couche et donc avec une capacité de modélisation limitée; pour le problème qui nous intéresse cela est suffisant. Pour plus de détails, revenez au cours

Exercice : Complétez le code ci-dessous, où l’on définit un modèle de type Perceptron avec comme paramètres \(10^{-3}\) pour la tolérence, \(36\) pour l’état aléatoire (random state) et 100 époques (max_iter)

from sklearn.linear_model import Perceptron

# définition du modèle de classificateur
# YOUR CODE HERE
raise NotImplementedError()
# on l'ajuste aux données d'entrainement

# YOUR CODE HERE
raise NotImplementedError()

# on calcule ensuite le taux d'erreur lors de l'entrainement et pour le test

# YOUR CODE HERE
raise NotImplementedError()

# on calcule les taux d'erreurs

# YOUR CODE HERE
raise NotImplementedError()
print("Classificateur: Perceptron")
print("Training error:", e_tr)
print("Test error:", e_te)

Exercice : Lisez la documentation de Perceptron. À quoi correspond le paramètre random_state ?

VOTRE RÉPONSE ICI

# YOUR CODE HERE
raise NotImplementedError()

Exercice : Complétez la table error_rates avec ce modèle.

# YOUR CODE HERE
raise NotImplementedError()
error_rates
assert error_rates.shape[0] >= 4
assert error_rates.shape[1] == 2

\(\clubsuit\) Points bonus : construction du classificateur «une règle» (One Rule)

Faites cette partie ou bien passez directement à la conclusion.

En complétant le code ci-dessous, créez votre premier classificateur qui:

  • sélectionne le « bon » attribut (rougeur ou élongation pour le problème des pommes/bananes), appelé \(G\) (pour good). C’est l’attribut qui est le plus corrélé (en valeur absolue, toujours !) aux valeurs cibles \(y = ± 1\);

  • détermine une valeur seuil (threshold);

  • utilise l’attribut G et le seuil pour prédire la classe des éléments.

Un canevas de la classe OneRule est fournit dans la classe utilities.py; vous pouvez le compléter ou bien la programmer entièrement vous même.

Ce classificateur est-il basé sur les attributs ou sur les exemples?

# Use this code to test your classifier
classifier = OneRule()
classifier.fit(Xtrain, Ytrain) 
Ytrain_predicted = classifier.predict(Xtrain)
Ytest_predicted = classifier.predict(Xtest)
e_tr = error_rate(Ytrain, Ytrain_predicted)
e_te = error_rate(Ytest, Ytest_predicted)
print("Classificateur: One rule")
print("Training error:", e_tr)
print("Test error:", e_te)

Exercice : Complétez la table error_rates avec ce modèle.

# YOUR CODE HERE
raise NotImplementedError()
print(error_rates)
assert error_rates.shape[0] >= 5
assert error_rates.shape[1] == 2
# On charge les images
dataset_dir = os.path.join(data.dir, 'ApplesAndBananasSimple')
images = load_images(dataset_dir, "*.png")
# This is what you get as decision boundary.
# The training examples are shown as white circles and the test examples are blue squares.
make_scatter_plot(X, images.apply(transparent_background_filter),
                  [], test_index, 
                  predicted_labels='GroundTruth',
                  feat = classifier.attribute, theta=classifier.theta, axis='square')

Comparez avec ce que vous auriez obtenu en utilisant les 2 attributs avec le même poids lors de la décision de classe.

make_scatter_plot(X, images.apply(transparent_background_filter),
                  [], test_index, 
                  predicted_labels='GroundTruth',
                  show_diag=True, axis='square')

Conclusion

Exercice : Comparez les taux d’erreur et d’entraînement de vos différents classificateurs pour le problème des pommes et des bananes.

VOTRE RÉPONSE ICI

Dans cette feuille vous avez découvert comment utiliser un certain nombre de classificateurs, voire comment implanter le vôtre, et comment jouer sur les paramètres de ces classificateurs (par exemple la tolérance du perceptron ou le nombre de voisins du KNN) pour essayer d’optimiser leur performance.

Mettez à jour votre rapport et déposez votre travail.

Vous êtes maintenant prêts pour revenir à votre analyse de données pour mettre en œuvre ces classificateurs sur votre jeu de données.

Dans le projet 1, on vous demande de choisir un seul classificateur, ainsi que ses paramètres. Nous verrons dans la seconde partie de l’UE comment comparer systématiquement les classificateurs.