Exemple "Jouet": Discrimination de blobs de

Résumé: Les méthodes de discrimination sont comparées sur un jeu de données fictif obtenu par la commande make_blobs de Scikit-learn. L'objectif est de mettre en évidence le rôle des paramètres de complexité de différentes méthodes (régression logistique, k-nn, réseaux de neurones, arbre de décision, bagging, svm) et de comparer les formes spécifiques des frontières estimées par chacune d'elle. Cela permet d'illustrer les principales méthodes d'apprentissage de Scikit-learn

1 Introduction

Les données se présentent sous la forme de nuages de points dans R2 plus présentant des groupes plu sou moins distincts ou mélangés. L'objectif est d'apprendre ces données très particulières afin de discriminer les deux classes. Les données étant simplement dans R2, il est facile de prévoir la classe de chaque point du plan et ainsi de visualiser la frontière entre les prévisions des deux classes. L'intérêt est de représenter ainsi facilement le rôle jouer par les paramètres de complexité de chaque méthode et de comparer les formes des frontières obtenues et donc la plus ou moins bonne adéquation d'une méthode à la spécificité de ces données simulées.


In [ ]:
%matplotlib inline
from matplotlib import pyplot as plt
# option d'impression
import numpy as np
np.set_printoptions(precision=3)

2 Génération des données

Génération aléatoire de 20 groupes de nuages de 1000 points dans R2. Le générateur de nombres aléatoires est initialisés par souci de reproductibilité. Les points sont séparés en deux classes.


In [ ]:
from sklearn.datasets import make_blobs

X, y = make_blobs(n_samples=1000, centers=20, random_state=123)
labels = ["b", "r"]
y = np.take(labels, (y < 10))
print(X)
print(y[:5])

Représentation des données dans le plan.


In [ ]:
plt.figure()
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.xlim(-10, 10)
plt.ylim(-10, 10)
plt.show()

3 Les classifieurs de Scikit-learn

Tous les algorithmes et méthodes de Scikit-learn se présentent sous la forme d'une combinaison de 3 "interfaces":

  • estimation pour ajuster des modèles,
  • prévision pour de nouvelles observations,
  • transformation pour convertir des données.

Celles-ci peuvent être facilement combinées et enchaînées en un pipeline.

3.1 k plus proches voisins

Estimation


In [ ]:
# Importation de la fonction
from sklearn.neighbors import KNeighborsClassifier  
# Détermination des paramètres et définition de l'estimateur
knnF = KNeighborsClassifier(n_neighbors=5)

# Apprentissage ou estimation du modèle sur l'échantillon d'apprentissage 
# mais il ne se passe rien  dans le cas de *k*-nn avant en dehors de la phase de prévision. 
knnF.fit(X, y)
# Les options de cet algorithmes:

Prévision

Prévision de la classe des 5 premiers points


In [ ]:
print(knnF.predict(X[:5]))

Ou de la probabilité des classes.


In [ ]:
print(knnF.predict_proba(X[:5]))

La fonction définie ci-dessous prévoit chaque point d'une grille du plan et trace un graphe de contour des probabilités.


In [ ]:
def plot_surface(clf, X, y, xlim=(-10, 10), ylim=(-10, 10), n_steps=250):
    fig = plt.figure()
    xx, yy = np.meshgrid(np.linspace(xlim[0], xlim[1], n_steps), np.linspace(ylim[0], ylim[1], n_steps))
    if hasattr(clf, "decision_function"):
        z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
    else:
        z = clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1]      
    z = z.reshape(xx.shape)
    plt.contourf(xx, yy, z, alpha=0.8, cmap=plt.cm.RdBu_r)
    plt.scatter(X[:, 0], X[:, 1], c=y)
    plt.xlim(*xlim)
    plt.ylim(*ylim)
    plt.show()

In [ ]:
knnF = KNeighborsClassifier(n_neighbors=70)
knnF.fit(X, y)
plot_surface(knnF, X, y)

Ce qui donne une bonne idée de la forme des frontières estimées entre les classes.

Faire varier le paramère n_neighbors (1 à 500) et observer l'impact sur la forme des classes.

3.2 Arbre binaire de décision

Les frontières sont construites à partir de parallèles aux axes. Faire varier la profondeur maximale max_depth de l'arbre.


In [ ]:
from sklearn.tree import DecisionTreeClassifier 
treeF = DecisionTreeClassifier(max_depth=10)
treeF.fit(X, y)
plot_surface(treeF, X, y)

3.3 Forêts aléatoires

Obtenues par agrégation d'arbres, une forêt arrondit les frontières. Avec seulement 2 variables (dans R2), cela revient à faire du bagging. Faire variaer le nombre d'arbres: n_estimators (1 à 20), de la forêt.


In [ ]:
from sklearn.ensemble import RandomForestClassifier 
rfF = RandomForestClassifier(n_estimators=200)
rfF.fit(X, y)
plot_surface(rfF, X, y)

3.4 Séparateur à Vaste Marge (SVM)

SVM linéaire, pas très intéressant sur ces données, puis gaussien. Faire varier la pénalisation C et l'étendue du noyau gaussien.


In [ ]:
# Noyau linéaire
from sklearn.svm import SVC
svmF = SVC(kernel="linear",C=1)  # try kernel="rbf" instead
svmF.fit(X, y)
plot_surface(svmF, X, y)

Faire varier C de 10-5 à 10^5, gamma de 0.001 à 100


In [ ]:
# Noyau gaussien avec valeurs par défaut de C et gamma
from sklearn.svm import SVC
svmF = SVC(kernel="rbf", C=1, gamma='auto')  
svmF.fit(X, y)
plot_surface(svmF, X, y)

3.5 Perceptron multicouches

Faire varier le nombre de couches cachées, le nombe de neurones sur ces couches, la pénalisation l2 alpha.


In [ ]:
# Trois couches de 100 neurones avec alpha par défaut
from sklearn.neural_network import MLPClassifier
nnetF = MLPClassifier(hidden_layer_sizes=(100, 100, 100),alpha=0.0001)
nnetF.fit(X, y)
plot_surface(nnetF, X, y)

3.6 Processus gaussien

Consulter la doc en ligne.


In [ ]:
from sklearn.gaussian_process import GaussianProcessClassifier
pgF = GaussianProcessClassifier()
pgF.fit(X, y)
plot_surface(pgF, X, y)

Conclusion:

Q Quelles sont les méthodes ou modèles les plus adaptés à ces données? Est-ce généralisable à d'autres?