Classification non supervisée (CAH, kmeans, pam) et représentation des classes dans un plan factoriel avec des données sous différentes formes: tableau de distance et MDS, variables quantitatives et ACP, variables qualitatives et AFCM. Application à des exemples élémentaires.
Le nombre de méthodes de classification non supervisée (clustering) et le nombre d'options dans chacune d'elles conduisent à une combinatoire de possibilités assez impressionnante. Le but est de mettre en évidence, de façon heuristique et dans des cas simples, quels sont les paramètres qui influencent, de visu, les classes obtenues. Un rôle important est donc attribué à la représentation des classes dans un plan factoriel. Le choix de la méthode: analyse en composantes principales, analyse factorielle multiple des correspondances ou encore positionnement multidimensionnel, dépend du type (quantitatives, qualitatives, distances) des données analysées.
La plupart des analyses ci-dessous peuvent être reproduites avec SAS mais de façon nettement moins souple et pas toutes (PAM n'est pas implémenté).
le MultiDimensional Scaling, MDS ou encore ACP d'un tableau de distances s'applique à des données archivées sous la forme d'une matrice ($n\times n$) de distances ou dissimilarités. Cet algorithme est appliqué sur un exemple simple comparant des distances entre villes.
Les données se présentent donc sous la forme du triangle inférieur d'une matrice symétrique, par construction, et contenant les distances kilométriques routières, donc non-euclidiennes, de 47 villes française ou proches prises 2 à 2 (Source : carte IGN).
La lecture d'une matrice triangulaire inférieure en tant que matrice de distance pose quelques difficultés dans R dans la gestion du type des objets. Ceci nécessite une séquence de commandes pour la bonne mise en forme.
In [ ]:
mdsville=read.table("Data/mdsville.dat",fill=TRUE)
# extraction des noms des villes
villes=as.character(mdsville[2:48,1])
# extraction des valeurs des distances
m=mdsville[2:48,2:48]
# transformation en une matrice alphanumérique
m=as.matrix(m)
# retour au numérique avec données manquantes
m=as.numeric(m)
# reformattage en une matrice
m=matrix(m,47,47)
# adjonction des noms des villes en ligne et colonne
dimnames(m)[[1]]=villes
dimnames(m)[[2]]=villes
# transformation en un objet de type distance
d=as.dist(m,diag=TRUE)
In [ ]:
mds = cmdscale(d, k=2)
plot(mds, type="n", xlab="cp1", ylab="cp2")
text(mds,villes)
Q Commenter la représentation obtenue par rapport à la carte géographique.
Les mêmes données sont reprises en vue de regrouper les villes en classes homogènes au regard de leurs distances respectives.
Q Quel est le graphe ci-dessous? Commenter.
In [ ]:
chv = hclust(d, method="ward.D")
options(repr.plot.width=7, repr.plot.height=5)
plot(chv,main=NULL,sub="",xlab="")
Q Comment est définie la corrélation cophénétique?
In [ ]:
# cophenetic correlation
cor(cophenetic(chv),d)
Q Quel est le graphe ci-dessous? Quelle décision en tirer?
In [ ]:
options(repr.plot.width=4, repr.plot.height=4)
plot(chv$height[46:30],xlab="nb de classes",ylab="Hauteur")
Q Quel est le graphe ci-dessous? Commentaire.
In [ ]:
color=cutree(chv,k=5)
library(cluster)
options(repr.plot.width=6, repr.plot.height=5)
plot(silhouette(color,d))
Il est possible de calculer puis représenter la silhouette moyenne pour plusieurs valeurs du nombre de classes et tenter de minimiser cette valeur; cette stratégie conduisant à un choix ``trivial'' $(k=3)$ est laissée de côté.
Les données provenant d'une matrice de distances, le MDS s'impose pour une représentation fatorielle des villes.
In [ ]:
options(repr.plot.width=5, repr.plot.height=5)
plot(mds, type="n", xlab="cp1", ylab="cp2")
# représentation avec des couleurs
text(mds,villes,col=color)
Influence déterminante du choix de la distance entre groupe.
Q Quelles sont les options possibles de l'option method
de la fonction hclust
?
Q Que signifie le choix single
ci-dessous?
In [ ]:
chv <- hclust(d, method="single")
cor(cophenetic(chv),d)
Q Que devient la corrélation cophénétique?
In [ ]:
options(repr.plot.width=7, repr.plot.height=5)
plot(chv,main=NULL,sub="",xlab="")
In [ ]:
options(repr.plot.width=5, repr.plot.height=4)
plot(chv$height[46:30],xlab="nb de classes",ylab="Hauteur")
Q Le choix du nombre de classes est-il facile?
In [ ]:
color=cutree(chv,k=5)
options(repr.plot.width=5, repr.plot.height=5)
plot(mds, type="n", xlab="cp1", ylab="cp2")
text(mds,villes,col=color) # représentation avec des couleurs
Tester les autres options de distances entre groupes.
Q Conclusion: le critère de plus grande corrélation cophénétique est-il à considérer pour choisir l'option de distance entre les groupes?
L'algorithme de réallocation k-means n'est pas adapté à une matrice de distances ou de dissimilarités; en revanche, PAM (partition around medoïds) est opérationnel si le nombre d'observations n'est pas trop important; sinon utiliser l'adaptation {\tt clara}. Ces fonctions sont disponibles dans la librairie cluster
.
In [ ]:
library(cluster)
# faire varier le nombre de classes
plot(silhouette(pam(d,6)))
In [ ]:
pamv=pam(d,6)
color=pamv$clustering
plot(mds, type="n", xlab="cp1", ylab="cp2")
# représentation avec des couleurs
text(mds,villes,col=color)
In [ ]:
# le même avec des ellipses
clusplot(d,pamv$clustering,diss=TRUE,labels=2,color=TRUE,col.txt=pamv$clustering,main="")
Remarque: le critère de clusGap
pour la sélection du nombre de classe ne s'applique pas à une matrice de distances mais il pourrait s'appliquer aux coordonnées principales issues du MDS.
Les données du fichier ocdeR.dat
sont celles étudiées comme exemple d'ACP cubique avec SAS. Comme elles sont connues par une représentation euclidienne, la distance considérée par défaut est euclidienne mais d'autres choix sont possibles (manhattan ou valeurs absolues...).
Lecture des données puis construction de la matrice de distance.
Attention Il est important de centrer réduire des variables quantitatives avant de faire une classification
In [ ]:
ocde=read.table("Data/ocdeR.dat")
ds=dist(scale(ocde))
# classification hiérarchique
hc.ds = hclust(ds,method="ward.D")
options(repr.plot.width=8, repr.plot.height=5)
plot(hc.ds,main="") # dendogramme
In [ ]:
# choix du nombre de classes
options(repr.plot.width=4, repr.plot.height=4)
plot(hc.ds$height[67 :58],type="b")
In [ ]:
color= cutree(hc.ds,k=4) # couleurs des classes
# silhouette
library(cluster)
plot(silhouette(color,ds))
In [ ]:
# corrélation cophénétique
cor(cophenetic(hc.ds),ds)
In [ ]:
# acp pour représentations
library(FactoMineR)
acp=PCA(ocde,ncp=13,graph=F)
# graphe de l'acp
options(repr.plot.width=5, repr.plot.height=5)
plot(acp,choix="ind", habillage="ind",col.hab=rep(1:17, c(rep(4,17))))
In [ ]:
# graphe de l'acp avec les couleurs des classes de la cah
plot(acp,choix="ind", habillage="ind",col.hab=color)
Refaire tourner l'algorithme en retirant la réduction des variables (fonction scale), même chose en remplaçant method="ward.D"
par method="single"
.
Q Noter l'importance de la normalisation des variables.
Q Que choisir comme méthode?
In [ ]:
# version avec réduction
# choix de 4 classes suggérées par la cah
kocde=kmeans(scale(ocde),4)
color=kocde$cluster
plot(acp,choix="ind", habillage="ind",col.hab=color)
In [ ]:
# version sans réduction
kocde=kmeans(ocde,4)
color=kocde$cluster
plot(acp,choix="ind", habillage="ind",col.hab=color)
In [ ]:
# utilisation de clusGap
library(cluster)
clusGap(ocde, FUN = kmeans, K.max = 8, B = 60)
Plusieurs critères sont concurrents pour sélectionner un $k$ optimal une fois les calculs de clusGap
réalisés par bootsrap. le choix reste complexe.
Dans des situaitons de très grande dimension, il peut être intéressant de réduire celle-ci par ACP avant d'opérer une classification.
La librairie FactoMineR
propose cette possibilité avec la production de graphiques élaborées mais sans doute pas tous utiles et qui bloquent jupyter. Un autre paramètre est susceptible d'avoir un impact, le nombre ncp
de composantes retenues.
In [ ]:
acp=PCA(ocde,ncp=5,graph=F)
res.hcpc=HCPC(acp,graph=F,nb.clust=4)
In [ ]:
plot(acp, choix="ind", habillage="ind",col.hab=res.hcpc$data.clust$clust)
Q Que dire du choix de 4 classes? Revenir à 3.
Q Quelle option de classification vous semble la plus pertinente sur ces données OCDE?
Plusieurs stratégies sont proposées pour classées des données qualitatives ou mélange de variables quantitatives et qualitatives. La plus simple consiste à recoder les variables quantitatives en qualitatives puis de calculer des scores à l'aide des composantes d'une AFCM.
Les données (race des chiens) sont celles illustrant l'utilisation de l'AFCM; R est nettement plus souple que SAS pour enchaîner de telles analyses.
In [ ]:
chiens=read.csv("chiens.Data/csv",row.names=1)
summary(chiens)
Nous reprenons l'AFCM sur tableau disjonctif complet fournissant des scores ou variables quantitatives sur les individus, ici les races de chiens, il est alors facile de les classer. L'enchaînement par une CAH est la combinaison la plus simple à réaliser à l'aide de la librairie FactoMineR
. Attention néanmoins de bien contrôler les options qui toutes sont prises par défaut.
In [ ]:
library(FactoMineR)
#afcm avec la fonction en supplémentaire
afcm=MCA(chiens,quali.sup=7,graph=F)
plot(afcm, choix="ind",habillage="quali")
FactoMineR
propose des aides à l'interprétation des classees. La variable classe est croisée
avec chacune des variables. Un test du chi2 apprécie la liaison.
In [ ]:
res.hcpc=HCPC(afcm, graph=FALSE,order=FALSE,nb.clust=4)
res.hcpc$desc.var$test.chi2
Avant de mettre en évidence les modalités les plus "présentes" dans chaque classe.
In [ ]:
res.hcpc$desc.var$category
Justification a posteriori du choix du nombre de classes. Le choix par défaut (10) n'a pas d'intérêt.
In [ ]:
options(repr.plot.width=5, repr.plot.height=5)
plot(res.hcpc,choice="tree")
In [ ]:
plot(afcm, choix="ind", invisible="var",col.ind=res.hcpc$data.clust$clust)
In [ ]:
table(res.hcpc$data.clust$clust,res.hcpc$data.clust$fonction)
D'autres outils (arbre de discrimination) s'avéreront plus explicites pour interpréter les classes.
Q Combien de dimensions sont retenues par défaut dans cette AFCM?
Q Quelle distance est prise en compte entre les individus?
Q Quelle est l'option par défaut pour la distance entre les groupes?
D'autre par une option positionnée (consol=TRUE
) fait enchaîner automatiquement un algorithme k-means.
Q Que dire des options suivantes .
In [ ]:
afcm=MCA(chiens,quali.sup=7, ncp=10, graph=F)
res.hcpc=HCPC(afcm,method="single",graph=F,nb.clust=4)
table(res.hcpc$data.clust$clust,res.hcpc$data.clust$fonction)
En fait les classes se distinguent assez facilement et restent stables sur ces données sauf en cas d'utilisation du saut minimum.
Bien entendu, la fonction HCPC
de FactoMineR
pourrait être remplacée par tout autre algorithme de classification avec ses propres options: hclust, kmeans, pam...
.