Tutoriel sur les procédures de package python : CAH et k-Means

Ricco.Rakotomalala
Importation des données, description
DONNÉES
Objectifs de l’étude
Ce document retranscrit une démarche de classification automatique d’un ensemble de fromages (29 observations) décrits par leurs propriétés nutritives (ex. protéines, lipides, etc. ; 9 variables). L’objectif est d’identifier des groupes de fromages homogènes, partageant des caractéristiques similaires.
Nous utiliserons essentiellement deux approches en nous appuyant sur deux procédures des packages spécialisés pour Python : la classification ascendante hiérarchique (CAH – Package SciPy) ; la méthode des centres mobiles (k-Means – Package Scikit-Learn).
Le fichier « » provient de la page de coursde Marie Chavent de l’Université de Bordeaux. Les excellents supports et exercices corrigés que l’on peut y trouver compléteront à profit ce tutoriel qui se veut avant tout un guide simple pour une première prise en main de Python dans le contexte de la classification automatique.
Traitements réalisés
• Chargement et description des données
• Classification automatique
• Pistes pour la détection du nombre adéquat de classes
• Description – interprétation des groupes
#modification du dossier par défaut import os os.chdir("…") #importation des données import pandas fromage = pandas.read_table("",sep="\t",header=0,index_col=0) #dimension des données print(fromage.shape) #statistiques descriptives print(fromage.describe()) #graphique - croisement deux à deux des variables from pandas.tools.plotting import scatter_matrix scatter_matrix(fromage,figsize=(9,9)) | ||||
| ||||
Classification ascendante hiérarchique
CAH
#librairies pour la CAH from matplotlib import pyplot as plt from scipy.cluster.hierarchy import dendrogram, linkage #générer la matrice des liens Z = linkage(fromage_cr,method='ward',metric='euclidean') #affichage du dendrogramme plt.title("CAH") dendrogram(Z,labels=fromage.index,orientation='left',color_threshold=0) () |
Le dendrogramme « suggère » un découpage en 4 groupes. On note qu’une classe de fromages, les « fromages frais » (tout à gauche), se démarque fortement des autres au point qu’on aurait pu envisager aussi un découpage en 2 groupes seulement. Nous y reviendrons plus longuement lorsque nous mixerons l’analyse avec une analyse en composantes principales (ACP).
Classification ascendante hiérarchique
Découpage en classes – Matérialisation des groupes
#matérialisation des 4 classes (hauteur t = 7) plt.title('CAH avec matérialisation des 4 classes') dendrogram(Z,labels=fromage.index,orientation='left',color_threshold=7) () #découpage à la hauteur t = 7 ==> identifiants de 4 groupes obtenus groupes_cah = fcluster(Z,t=7,criterion='distance') print(groupes_cah) #index triés des groupes import numpy as np idg = np.argsort(groupes_cah) #affichage des observations et leurs groupes print(pandas.DataFrame(fromage.index[idg],groupes_cah[idg])) |
Groupe | Fromage |
1 | . |
1 | Fr.frais20nat. |
1 | Petitsuisse40 |
1 | Fr.frais40nat. |
2 | Fr.chevrepatemolle |
2 | Camembert |
2 | Chabichou |
2 | Chaource |
3 | Emmental |
3 | Parmesan |
3 | Beaufort |
3 | Comte |
4 | Pyrenees |
4 | PontlEveque |
4 | Rocquefort |
4 | SaintPaulin |
4 | Tome |
4 | Reblochon |
4 | CarredelEst |
4 | Maroilles |
4 | Vacherin |
4 | Edam |
4 | Coulomniers |
4 | Cheddar |
4 | Cantal |
4 | Bleu |
4 | Babybel |
4 | Morbier |
4 | Fr.fondu.45 |
Le 1er groupe est constitué de fromages frais. Le 2nd de fromages à pâte molle. Le 3ème de fromages « durs ». Le 4ème est un peu fourre-tout (de mon point de vue). Mes compétences en fromage s’arrêtent là (merci à Wikipédia). Pour une caractérisation à l’aide des variables de l’étude, il faut passer par des techniques statistiques univariées (simples à lire) ou multivariées (tenant compte des relations entre les variables). |
R.R. – Université Lyon 2
Méthode des centres mobiles
K-MEANS
Méthode des centres mobiles
Aide à la détection du nombre adéquat de groupes
K-MEANS, à la différence de la CAH, ne fournit pas d’outils d’aide à la détection du nombre de classes. Nous devons les programmer sous Python ou utiliser des procédures proposées par des packages dédiés. Le schéma est souvent le même : on fait varier le nombre de groupes et on surveille l’évolution d’un indicateur de qualité de la solution c.-à-d. l’aptitude des individus à être plus proches de ses congénères du même groupe que des individus des autres groupes.
Dans ce qui suit, on calcule la métrique « silhouette » pour différents nombres de groupes issus de la méthode des centres mobiles.
#librairie pour évaluation des partitions from sklearn import metrics #utilisation de la métrique "silhouette" #faire varier le nombre de clusters de 2 à 10 res = np.arange(9,dtype="double") for k in np.arange(9): km = cluster.KMeans(n_clusters=k+2) (fromage_cr) res[k] = metrics.silhouette_score(fromage_cr,km.labels_) print(res) #graphique import matplotlib.pyplot as plt plt.title("Silhouette") plt.xlabel("# of clusters") (np.arange(2,11,1),res) () |
Analyses univariées et multivariées
INTERPRÉTATION DES CLASSES
L’idée est de comparer les moyennes des variables actives conditionnellement aux groupes. Il est possible de quantifier globalement l’amplitude des écarts avec la proportion de variance expliquée (carré du rapport de corrélation). La démarche peut être étendue aux variables illustratives. Pour les catégorielles, nous confronterions les distributions conditionnelles.
L’approche est simple et les résultats faciles à lire. Rappelons cependant que nous ne tenons pas compte des liaisons entre les variables dans ce cas.
Effec. Cond.
#moyenne par variable 0 4 m = () 1 5
#TSS 2 6
TSS = fromage.shape[0]*(ddof=0) 3 14 print(TSS)
#data.frame conditionnellement aux groupes
gb = fromage.groupby(kmeans.labels_) Carré Rapport de corr. #effectifs conditionnels calories 0.863799 nk = () sodium 0.599117 print(nk) calcium 0.620108
#moyennes conditionnelles lipides 0.851983 mk = () retinol 0.382815 print(mk) folates 0.760722
#pour chaque groupe écart à la moyenne par proteines 0.810316 variable cholesterol 0.797596 EMk = (mk-m)**2 magnesium 0.796207
#pondéré par les effectifs du groupe La définition des groupes est – avant EM = EMk.multiply(nk,axis=0) tout – dominée par les teneurs en
#somme des valeurs => BSS graisses (lipides, cholestérol et
BSS = (EM,axis=0)
print(BSS) calories relèvent de la même idée) et
#carré du rapport de corrélation en protéines.
#variance expliquée par l'appartenance aux groupes
#pour chaque variable Le groupe n°0 est fortement R2 = BSS/TSS déterminé par ces variables, les print(R2)
moyennes conditionnelles sont très différentes.
Moyennes conditionnelles calories sodium calcium lipides retinol folates
0 101.750000 44.750000 133.75 6.275000 55.150000 16.475000
1 377.200000 130.400000 278.98 29.460000 64.560000 3.120000
2 288.000000 252.916667 110.10 23.866667 95.866667 31.266667
3 334.285714 267.428571 199.70 27.500000 60.050000 7.728571
proteines cholesterol magnesium
0 7.200000 18.250000 11.250000
1 29.120000 102.000000 45.400000
2 18.883333 68.333333 21.666667
3 21.228571 83.571429 27.142857
Avec l’ACP, nous tenons compte des liaisons entre les variables. L’analyse est plus riche. Mais il faut savoir lire correctement les sorties de l’ACP.
#ACP from sklearn.decomposition import PCA acp = PCA(n_components=2).fit_transform(fromage_cr) #projeter dans le plan factoriel #avec un code couleur différent selon le groupe #remarquer le rôle de zip() dans la boucle for couleur,k in zip(['red','blue','lawngreen','aqua'],[0,1,2,3]): plt.scatter(acp[kmeans.labels_==k,0],acp[kmeans.labels_==k,1],c=couleur) () |
Il y a un problème. Le groupe des fromages frais (n° de groupe = 0) écrase l’information disponible et tasse les autres fromages dans un bloc qui s’oriente différemment.
De fait, si l’on comprend bien la nature du groupe n°0 des fromages frais, les autres sont plus compliqués à comprendre lorsqu’ils sont replacés dans le premier plan factoriel.
A la lumière des résultats de l’ACP
COMPLÉTER L’ANALYSE
Les fromages frais sont tellement particuliers – éloignés de l’ensemble des autres observations – qu’ils masquent des relations intéressantes qui peuvent exister entre ces produits. Nous reprenons l’analyse en les excluant des traitements.
#retirer des observations le groupe n°0 du k-means précédent fromage_subset = [kmeans.labels_!=0,:] print(fromage_subset.shape) #centrer et réduire fromage_subset_cr = preprocessing.scale(fromage_subset) #générer la matrice des liens Z_subset = linkage(fromage_subset_cr,method='ward',metric='euclidean') #cah et affichage du dendrogramme plt.title("CAH") dendrogram(Z_subset,labels=fromage_subset.index,orientation='left',color_threshold=7) () #groupes groupes_subset_cah = fcluster(Z_subset,t=7,criterion='distance') print(groupes_subset_cah) |
moins le phénomène d’écrasement constaté dans l’analyse précédente.
#ACP acp_subset = PCA(n_components=2).fit_transform(fromage_subset_cr) #projeter dans le plan factoriel #avec un code couleur selon le groupe #remarquer le rôle dezip() plt.figure(figsize=(10,10)) for couleur,k in zip(['blue','lawngreen','aqua'],[1,2,3]): plt.scatter(acp_subset[groupes_subset_cah==k,0],acp_subset[groupes_subset_cah==k,1],c=couleur) #mettre les labels des points #remarquer le rôle deenumerate() for i,label in enumerate(fromage_subset.index): plt.annotate(label,(acp_subset[i,0],acp_subset[i,1])) () |
Les groupes sont constitués essentiellement sur le 1er facteur.
Quelques fromages ont changé de camp par rapport à l’analyse précédente.
Références :
1. Chavent M. , - Source des données « »
2. Jörn’s Blog, « SciPyHierarchicalClusteringandDendrogramTutorial».
3. , « Scikit-learn: machinelearning in Python».