Apprentissage paresseux (lazy learning): pas d’entraînement explicite
Le “modèle” est le jeu de données
KNN - Inférence
Classification/régression en fonction des étiquettes/valeurs des \(k\) exemples les plus proches dans l’espace des attributs
Définition formelle
Étant donné un jeu de données\(\{(x_i, y_i)\}_1^{N}\) et un exemple non vu\(x\) :
Calculer les distances\(d(x, x_i)\)
Sélectionner les \(k\) plus petites distances
Classification : vote majoritaire (possiblement pondéré par \(1/d\))
Régression : moyenne (possiblement pondérée)
Exercices
Téléchargez ces exemples pour expérimenter avec des variations de code. Notamment, examinez comment les changements de \(k\) influencent les frontières de décision en classification et la douceur de la ligne de régression.
Un arbre de décision est une structure hiérarchique représentée sous forme de graphe orienté acyclique, utilisée pour les tâches de classification et de régression.
Chaque nœud interne effectue un test binaire sur un attribut particulier (\(j\)), tel que si le nombre de connexions dans une école dépasse un seuil spécifié.
Les feuilles fonctionnent comme des nœuds de décision.
Classification de nouvelles instances (Inférence)
Commencez par le nœud racine de l’arbre de décision. Procédez en répondant à une série de questions binaires jusqu’à atteindre un nœud feuille. L’étiquette associée à cette feuille indique la classification de l’instance.
Alternativement, certains algorithmes peuvent stocker une distribution de probabilité au niveau de la feuille, représentant la fraction d’échantillons d’entraînement correspondant à chaque classe \(k\), parmi toutes les classes possibles \(k\).
Frontière de décision
Manchots de Palmer
# Chargement de notre jeu de donnéestry:from palmerpenguins import load_penguinsexcept:! pip install palmerpenguinsfrom palmerpenguins import load_penguinspenguins = load_penguins()# Pairplot avec seabornimport matplotlib.pyplot as pltimport seaborn as snssns.pairplot(penguins, hue='species', markers=["o", "s", "D"])plt.suptitle("Graphiques de dispersion par paires des attributs des manchots")plt.show()
Manchots de Palmer
Problème de classification binaire
Plusieurs graphiques de dispersion révèlent un regroupement distinct des instances Gentoo.
Pour illustrer notre prochain exemple, nous proposons un modèle de classification binaire : Gentoo contre non-Gentoo.
Notre analyse se concentrera sur deux attributs clés : masse corporelle et profondeur du bec.
Définition
Une frontière de décision est une “frontière” qui partitionne l’espace des attributs sous-jacent en régions correspondant à différentes étiquettes de classe.
Frontière de décision
La frontière de décision entre ces attributs peut être représentée comme une ligne.
Code
# Importer les bibliothèques nécessairesimport numpy as npfrom sklearn.linear_model import LogisticRegressionfrom sklearn.model_selection import train_test_splittry:from palmerpenguins import load_penguinsexcept:! pip install palmerpenguinsfrom palmerpenguins import load_penguins# Charger le jeu de données Palmer Penguinsdf = load_penguins()# Conserver uniquement les attributs nécessaires : 'bill_depth_mm' et 'body_mass_g'features = ['bill_depth_mm', 'body_mass_g']df = df[features + ['species']]# Supprimer les lignes avec des valeurs manquantesdf.dropna(inplace=True)# Créer un problème binaire : 'Gentoo' contre 'Pas Gentoo'df['species_binary'] = df['species'].apply(lambda x: 1if x =='Gentoo'else0)# Définir la matrice de attributs X et le vecteur cible yX = df[features].valuesy = df['species_binary'].values# Diviser les données en ensembles d'entraînement et de testX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# Fonction pour tracer le nuage de points initialdef plot_scatter(X, y): plt.figure(figsize=(9, 5)) plt.scatter(X[y ==1, 0], X[y ==1, 1], color='orange', edgecolors='k', marker='o', label='Gentoo') plt.scatter(X[y ==0, 0], X[y ==0, 1], color='blue', edgecolors='k', marker='o', label='Pas Gentoo') plt.xlabel('Profondeur du Bec (mm)') plt.ylabel('Masse Corporelle (g)') plt.title('Nuage de Points de la Profondeur du Bec vs. Masse Corporelle') plt.legend() plt.show()# Tracer le nuage de points initialplot_scatter(X_train, y_train)
Frontière de décision
Frontière de décision
La frontière de décision entre ces attributs peut être représentée par une ligne.
Code
# Entraîner un modèle de régression logistiquemodel = LogisticRegression()model.fit(X_train, y_train)# Fonction pour tracer la frontière de décisiondef plot_decision_boundary(X, y, model): x_min, x_max = X[:, 0].min() -1, X[:, 0].max() +1 y_min, y_max = X[:, 1].min() -1, X[:, 1].max() +1 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1)) Z = model.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) plt.figure(figsize=(9, 5)) plt.contourf(xx, yy, Z, alpha=0.3, cmap='RdYlBu') plt.scatter(X[y ==1, 0], X[y ==1, 1], color='orange', edgecolors='k', marker='o', label='Gentoo') plt.scatter(X[y ==0, 0], X[y ==0, 1], color='blue', edgecolors='k', marker='o', label='Non Gentoo') plt.xlabel('Profondeur du Bec (mm)') plt.ylabel('Masse Corporelle (g)') plt.title('Frontière de Décision de Régression Logistique') plt.legend() plt.show()# Tracer la frontière de décision sur l'ensemble d'entraînementplot_decision_boundary(X_train, y_train, model)
Frontière de décision
Définition
On dit que les données sont linéairement séparables lorsque deux classes de données peuvent être parfaitement séparées par une unique frontière linéaire, telle qu’une droite dans un espace bidimensionnel ou un hyperplan dans des dimensions supérieures.
Frontière de décision simple
(a) données d’entraînement, (b) courbe quadratique, et (c) fonction linéaire.
Les arbres de décision sont capables de générer des frontières de décision irrégulières et non linéaires.
Attribution :ibidem.
Définition (révisée)
Une frontière de décision est une hypersurface qui partitionne l’espace des caractéristiques sous-jacent en régions correspondant à différentes étiquettes de classe.
Arbre de décision (suite)
Construire un arbre de décision
Comment construire (apprendre) un arbre de décision ?
Y a-t-il des arbres qui sont “meilleurs” que d’autres ?
Est-il possible de construire un arbre de décision optimal de manière efficace sur le plan computationnel ?
Optimalité
Soit \(X = \{x_1, \ldots, x_n\}\) un ensemble fini d’objets.
Soit \(\mathcal{T} = \{T_1, \ldots, T_t\}\) un ensemble fini de tests.
Pour chaque objet et test, nous avons :
\(T_i(x_j)\) est soit vrai soit faux.
Un arbre optimal est celui qui identifie complètement tous les objets dans \(X\) et pour lequel \(|T|\) est minimal.
Construction d’un arbre de décision
Développement itératif : Commencez avec un arbre vide. Introduisez progressivement des nœuds, chacun informé par le jeu de données d’entraînement, jusqu’à ce que le jeu de données soit complètement classé ou que d’autres critères d’arrêt, tels que la profondeur maximale de l’arbre, soient atteints.
Construction d’un arbre de décision
Construction initiale du nœud :
Pour établir le nœud racine, évaluez toutes les \(D\) attributs disponibles.
Pour chaque attributs, évaluez différentes valeurs seuils dérivées des données observées dans le jeu d’entraînement.
Construction d’un arbre de décision
Pour un attribut numérique, l’algorithme considère tous les points de division possibles (seuils) dans la plage de l’attribut.
Ces points de division sont généralement les milieux entre deux valeurs uniques triées consécutives de l’attribut.
Construction d’un arbre de décision
Pour un attribut catégoriel avec \(k\) valeurs uniques, l’algorithme considère toutes les manières possibles de diviser les catégories en deux groupes.
Par exemple, si l’attribut (prévision météorologique) a les valeurs ‘Pluvieux’, ‘Nuageux’ et ‘Ensoleillé’, il évalue les divisions suivantes :
\(\{\mathrm{Pluvieux}\}\) vs. \(\{\mathrm{Nuageux}, \mathrm{Ensoleillé}\}\),
\(\{\mathrm{Nuageux}\}\) vs. \(\{\mathrm{Pluvieux}, \mathrm{Ensoleillé}\}\),
\(\{\mathrm{Ensoleillé}\}\) vs. \(\{\mathrm{Pluvieux}, \mathrm{Nuageux}\}\).
Évaluation
Qu’est-ce qui définit une “bonne” séparation des données ?
\(\{\mathrm{Pluvieux}\}\) vs. \(\{\mathrm{Nuageux}, \mathrm{Ensoleillé}\}\) : \([20,10,5]\) et \([10,10,15]\).
\(\{\mathrm{Nuageux}\}\) vs. \(\{\mathrm{Pluvieux}, \mathrm{Ensoleillé}\}\) : \([40,0,0]\) et \([0,30,0]\).
Évaluation
Hétérogénéité (également appelée impureté) et homogénéité sont des mesures pour évaluer la composition des partitions de données résultantes.
Idéalement, chacune de ces partitions devrait contenir des entrées de données d’une seule classe pour atteindre une homogénéité maximale.
L’entropie et l’indice de Gini sont deux mesures largement utilisées pour évaluer ces caractéristiques.
Évaluation
Fonction objective pour sklearn.tree.DecisionTreeClassifier (CART) :
Le coût de la partition des données en utilisant l’attribut\(k\) et le seuil\(t_k\).
\(N_{\text{gauche}}\) et \(N_{\text{droite}}\) sont le nombre d’exemples dans les sous-ensembles gauche et droite, respectivement, et \(N_{\text{parent}}\) est le nombre d’exemples avant la division des données.
\(G_{\text{gauche}}\) et \(G_{\text{droite}}\) sont l’impureté des sous-ensembles gauche et droite, respectivement.
Indice de Gini
Indice de Gini (par défaut)
\[
G_i = 1 - \sum_{k=1}^n p_{i,k}^2
\]
\(p_{i,k}\) est la proportion des exemples de cette classe \(k\) dans le nœud \(i\).
Quelle est la valeur maximale de l’indice de Gini ?
Indice de Gini
Considérant un problème de classification binaire :
\(1 - [(0/100)^2 + (100/100)^2] = 0\) (pur)
\(1 - [(25/100)^2 + (75/100)^2] = 0.375\)
\(1 - [(50/100)^2 + (50/100)^2] = 0.5\)
Indice de Gini
Code
def gini_index(p):"""Calculer l'indice de Gini."""return1- (p**2+ (1- p)**2)# Valeurs de probabilité pour la classe 1p_values = np.linspace(0, 1, 100)# Calculer l'indice de Gini pour chaque probabilitégini_values = [gini_index(p) for p in p_values]# Tracer l'indice de Giniplt.figure(figsize=(8, 6))plt.plot(p_values, gini_values, label='Indice de Gini', color='b')plt.title('Indice de Gini pour une Classification Binaire')plt.xlabel('Probabilité de la Classe 1 (p)')plt.ylabel('Indice de Gini')plt.grid(True)plt.legend()plt.show()
Jeu de données Iris
Exemple complet
Critères d’arrêt
Tous les exemples dans un nœud donné appartiennent à la même classe.
La profondeur de l’arbre dépasserait max_depth.
Le nombre d’exemples dans le nœud est min_sample_split ou moins.
Aucune des divisions ne réduit suffisamment l’impureté (min_impurity_decrease).
Voir la documentation pour d’autres critères.
Limitations
Peut créer des arbres de grande taille
Défi pour l’interprétation
Surapprentissage
Algorithme gourmand, aucune garantie de trouver l’arbre optimal. (Hyafil et Rivest 1976)
Petits changements dans l’ensemble de données produisent des arbres très différents
Arbres de grande taille
Petits changements dans l’ensemble de données
Code
from sklearn import treefrom sklearn.metrics import classification_report, accuracy_score# Chargement de l'ensemble de donnéesX, y = load_penguins(return_X_y =True)target_names = ['Adelie','Chinstrap','Gentoo']# Diviser l'ensemble de données en ensembles d'entraînement et de testfor seed in (4, 7, 90, 96, 99, 2):print(f'Seed: {seed}')# Créer de nouveaux ensembles d'entraînement et de test basés sur une graine aléatoire différente X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=seed)# Création d'un nouveau classificateur clf = tree.DecisionTreeClassifier(random_state=seed)# Entraînement clf.fit(X_train, y_train)# Faire des prédictions y_pred = clf.predict(X_test)# Tracé de l'arbre tree.plot_tree(clf, feature_names = X.columns, class_names = target_names, filled =True) plt.show()# Évaluation du modèle accuracy = accuracy_score(y_test, y_pred) report = classification_report(y_test, y_pred, target_names=target_names)print(f'Accuracy: {accuracy:.2f}')print('Rapport de Classification:')print(report)
Le cours a passé en revue trois algorithmes d’apprentissage : k-plus proches voisins (KNN), arbres de décision et régression linéaire, et les a présentés via leur modèle, objectif et optimisation.
Nous avons ensuite construit des arbres de décision, montré que les feuilles de régression retournaient la moyenne de l’échantillon, minimisé l’impureté pondérée \(J\), et analysé l’indice de Gini.
Les frontières de décision ont été illustrées pour les modèles linéaires et non linéaires.
Géron, Aurélien. 2019. Hands-on Machine Learning with Scikit-Learn, Keras, and TensorFlow. 2nd éd. O’Reilly Media.
Geurts, Pierre, Alexandre Irrthum, et Louis Wehenkel. 2009. « Supervised learning with decision tree-based methods in computational and systems biology ». Molecular bioSystems 5 (12): 1593‑1605. https://doi.org/10.1039/b907946g.
Hyafil, Laurent, et Ronald L. Rivest. 1976. « Constructing Optimal Binary Decision Trees is NP-Complete ». Inf. Process. Lett. 5 (1): 15‑17. https://doi.org/10.1016/0020-0190(76)90095-8.
Russell, Stuart, et Peter Norvig. 2020. Artificial Intelligence: A Modern Approach. 4ᵉ éd. Pearson. http://aima.cs.berkeley.edu/.
Stiglic, Gregor, Simon Kocbek, Igor Pernek, et Peter Kokol. 2012. « Comprehensive decision tree models in bioinformatics ». Édité par Ahmed Moustafa. PLoS ONE 7 (3): e33812. https://doi.org/10.1371/journal.pone.0033812.