Regroupement, catégorisation et classification
en langage python
L'essentiel de cette page
Cette page présente deux méthode de regroupements (clusterisation) : le k-means et la clusterisation hiérérachique ascendante.
Il reste à développement les méthodes de classification et catégorisation.
0- Création d'un jeu de données (exemple)
Copions-collons le jeu de données suivant afin d'avoir des données simulées :
import pandas as pd
# nécessite le module seaborn
import seaborn as sns
# Charger le jeu de données iris
iris = sns.load_dataset('iris')
print(iris.head(6))
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
5 5.4 3.9 1.7 0.4 setosa
Description de 3 espèces d'iris en fonctions de 4 types de mesures
1- Regrouper les points par la méthode des k-means (module sklearn)
from sklearn.cluster import KMeans
# On va voir si on retrouve 3 espèces :
donnees_mesurees = iris.iloc[:,0:4] # Les 4 premières colonnes
nombre_de_categories = 3
kmeans = KMeans(n_clusters=nombre_de_categories, random_state=0).fit(donnees_mesurees)
# Résultats
print(kmeans)
print(kmeans.labels_)
# Fonction de prédiction : on peut lui donner d'autres points pour valider un modèle
print(kmeans.predict(donnees_mesurees))
print(kmeans.cluster_centers_)
# Affichage des résultats avant
import matplotlib.pyplot as plt
# Utiliser les noms d'espèce pour colorier les points
iris["species"] = iris["species"].astype('category')
plt.subplot(211) ; plt.title("Vraies catégories")
plt.scatter(iris.sepal_length,iris.sepal_width,
c=iris.species.cat.codes) ;
# Affichage des résultats du k-means
plt.subplot(212) ; plt.title("Résultat du k-means")
centers = pd.DataFrame(kmeans.cluster_centers_) # Récupérer les centres pour les afficher
centers.columns = donnees_mesurees.columns ; print(centers)
plt.scatter(iris.sepal_length,iris.sepal_width,
c=list(kmeans.predict(donnees_mesurees))) ;
plt.scatter(centers.sepal_length,centers.sepal_width,
c=range(nombre_de_categories),s=200,marker="s")
plt.show()
On voit une certaine efficacité du k-means mais aussi beaucoup d'erreurs...
2- Clustering par segmentation hiérarchique ascendante
2.1- Mise en place du clustering
#librairies pour la CAH
from matplotlib import pyplot as plt
from scipy.cluster.hierarchy import dendrogram, linkage, fcluster
#générer la matrice des liens
Z = linkage(iris.iloc[:,0:4],method='ward',
metric='euclidean')
#affichage du dendrogramme
plt.title("CAH")
dendrogram(Z,labels=iris.index,orientation='left',
color_threshold=0)
plt.show()
Plusieurs méthode de linkage sont à tester : "single", "average", "weighted", "centroid" ou "ward".
De même, la distance peut être "euclidean”, “l1”, “l2”, “manhattan”, “cosine”, ou “precomputed”
Dendrogramme obtenu par classification hiérarchique ascendante
2.2- Réaliser un diagramme d'inertie (Scree plot) pour définir le nombre optimal de catégories/classes
import numpy as np
last = Z[-10:, 2]
last_rev = last[::-1]
idxs = np.arange(2, len(last) + 2)
plt.step(idxs, last_rev, c="black")
plt.xlabel("Nombre de classes")
plt.ylabel("Inertie")
nombre = 3 # Ici, on teste le scénario où il y aurait 3 catégories
plt.scatter(idxs[np.where(idxs==nombre)], last_rev[np.where(idxs==nombre)], c="red")
plt.axvline(idxs[np.where(idxs==nombre)], c="red")
plt.show()
Extrait de code s'inspirant du travail remarquable du blog de Jörn.
On voit sur ce graphique 2 grands sauts d'inertie pour 2 et 3 classes. Cela suggère bien qu'une découpe en 2 ou 3 serait pertinente, mais pas au delà !
2.3- Découper le dendrogramme pour déterminer les catégories
#matérialisation des 3 espèces (hauteur t = 7 à 10)
plt.title('CAH avec matérialisation des 3 espèces')
dendrogram(Z,labels=iris.index,orientation='left',color_threshold=7)
plt.show()
#découpage à la hauteur t = 7 : 3 groupes obtenus
groupes_cah = fcluster(Z,t=7,criterion='distance')
print(groupes_cah)
2.4- Afficher les résultats en scatter-plot
iris["species"] = iris["species"].astype('category')
plt.subplot(211) ; plt.title("Vraies catégories")
plt.scatter(iris.petal_length,iris.sepal_width,
c=iris.species.cat.codes) ;
# Affichage des résultats du k-means
plt.subplot(212) ; plt.title("Résultat du CAH")
plt.scatter(iris.petal_length,iris.sepal_width,
c=groupes_cah) ;
plt.show()
Est-ce mieux que les k-means ? En général, l'expérience montre que oui ! Car les k-means se trompent rapidement dès que les groupes par catégories dessinent des nuages trop proches ou des formes imbriquées.
3- Combiner clusters et heatmaps
3.1- Reprenons le chargement des données iris
import seaborn as sns
# Charger le jeu de données iris
iris = sns.load_dataset('iris')
print(iris.head(6))
Les données sont dans les 4 premières colonnes. La cinquième présente les solutions (nom des espèces).
sepal_length sepal_width petal_length petal_width species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
5 5.4 3.9 1.7 0.4 setosa
3.2- Affichage d'un clustermap : clusters + heatmap
import matplotlib.pyplot as plt
# Ne pas oublier de charger aussi seaborn
sns.clustermap(iris.iloc[:,0:4])
plt.show()
3.3- On peut faire la même chose en centrant-réduisant (centrer-réduire) les données.
# Etape 1 - Centrer les données contenues dans la dataframe iris
# soustraire la moyenne
temp = iris.iloc[:,0:4].sub(iris.iloc[:,0:4].mean())
# Etape 2 - Réduire les données
# diviser par l'écart-type
temp = temp.div(temp.std())
# Affichage
sns.clustermap(temp)
plt.show()
3.4- Paramétrer les méthodes de calcul de la distance et de clusterisation (regroupement).
sns.clustermap(temp,method='ward',metric='euclidean')
plt.show()
Plusieurs méthode de linkage (method) sont à tester : , "single", "average", "weighted", "centroid" ou "ward".
De même, la distance (metric) peut être "correlation","euclidean”, “l1”, “l2”, “manhattan”, “cosine”, ou “precomputed”
Un autre paramètre standard_scale=1 (1 = action par colonne) est une méthode pour "centrer-réduire" par soustraction du minimum et divisé par le maximum
3.5- Configurer l'affichage, les couleurs (colorisation) :
# On réalise une palette de couleurs avec la fonction zip ==> Résultat de sortie, un dictionnaire
my_palette = dict(zip(iris.species.unique(), ["orange","yellow","brown"])) ; print(my_palette)
row_colors = iris.species.map(my_palette)
# Plot : On colorise les vraies espèces pour comparer résultat du clustering et réalité
sns.clustermap(temp, method="ward", metric="euclidean", cmap="Blues", standard_scale=1, row_colors=row_colors)
plt.show()
# cmap = doit être séquentiel comme "YlGnBu"