Chapitre 7 Classification (clustering)

Les méthodes de classification (= de partitionnement) servent à délimiter des groupes d’individus, ou typologies, à partir des caractéristiques de ces individus. En particulier, elles visent à distinguer des ensembles au sein desquels les individus se ressemblent plus qu’ils ne ressemblent aux individus des autres groupes.

Il faut être prudent dans leur interprétation : le fait que la méthode réussisse à délimiter des groupes ne démontre en rien la pertinence du découpage (c’est-à-dire l’existence de discontinuités entre des groupes plutôt homogènes). Ce n’est pas parce que vous avez découpé, avec un couteau, une tarte en 5 parts, que ce découpage reflète des discontinuités antérieures. Les méthodes de classifications sont, en quelques sortes, des couteaux …

7.1 Les k-moyennes

7.1.1 Principe

L’algorithme des k-moyennes (ou nuées dynamiques, k-means en anglais) consiste à regrouper les individus dans k classes les plus homogènes possibles. Son fonctionnement est très intuitif et il est très peu coûteux en termes de calcul :

  • l’utilisateur choisit le nombre de classes \(k\).
  • l’algorithme prend k points aléatoires (les centres) dans le nuage de point des individus.
  • chaque individu est affecté au centre le plus proche.
  • on calcule le barycentre des points de chaque classe consitutée \(\rightarrow\) les centres bougent.
  • on ré-affecte les individus au nouveau centre le plus proche
  • on répète les deux étapes précédentes jusqu’à ce que les barycentres ne “bougent plus”

Cet algorithme fonctionne sur des variables quantitatives ; on peut le mobiliser sur les coordonnées factorielles des individus et donc l’appliquer sur des variables initialement qualitative (après avoir fait une ACM / AFC). En pratique, il converge assez rapidement et est donc très efficace, même sur de grands jeux de données.

7.1.2 Mise en oeuvre

Exemple sur les hobbies :

## List of 9
##  $ cluster     : Named int [1:8403] 3 1 4 4 4 4 1 3 3 3 ...
##   ..- attr(*, "names")= chr [1:8403] "11000210" "11000410" "11000610" "11000710" ...
##  $ centers     : num [1:4, 1:4] -0.0806 -0.056 0.5301 -0.4031 0.2161 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:4] "1" "2" "3" "4"
##   .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##  $ totss       : num 3473
##  $ withinss    : num [1:4] 316 304 607 492
##  $ tot.withinss: num 1719
##  $ betweenss   : num 1753
##  $ size        : int [1:4] 1479 1594 2526 2804
##  $ iter        : int 5
##  $ ifault      : int 0
##  - attr(*, "class")= chr "kmeans"
## 
##    1    2    3    4 
## 1479 1594 2526 2804

Remarques :

  • Le nombre de classes est choisi de façon arbitraire (comment savoir si ce nombre est correct ?).
  • Les résultats changent selon les points initiaux choisis \(\Rightarrow\) 2 exécutions consécutives donneront 2 résultats différents ! Deux solutions pour avoir tout le temps le même résultat :
    • fournir les centres initiaux à l’algorithme.
    • fixer la “graine” du générateur de nombres aléatoires.

Pour récupérer les résultat dans son dataframe, il suffit de rajouter le vecteur résultat dans le dataframe initial :

Ici on remarque que les classes 2 et 3 s’opposent sur le premier plan factoriel : la classe 2 est plutôt du côté des personnes ayant peu de hobbies, à l’inverse de la classe 3 est composée d’individus ayant des occupations plutôt culturelles. Les classes 1 et 4 sont opposées sur l’axe 3, ce qui signifie que la 1 regroupe des individus aux loisirs plutôt domestiques et la 4 des individus ayant des loisirs de plein air.

7.1.3 Quelques conseils

Pour décrire les classes, on peut, en plus de la représentation sur les axes factoriels, faire un tableau croisé de cette nouvelle variable avec les variables initiales qualitatives ou calculer des rapports de corrélations avec les variables initiales quantitatives.

Pour choisir le nombre de classes, on peut :

  • tester plusieurs configuratons et choisir celle qui est la plus “parlante” (on est dans du descriptif, ne pas l’oublier !)
  • faire plusieurs classifications et choisir la meilleure au sens d’un indicateur du type \(\dfrac{1}{k} \dfrac{SS_{inter}}{SS_{total}}\)
  • repérer le nombre optimal avec une CAH

7.2 La classification ascendante hiérarchique (CAH)

Pourquoi cet acronyme ?

  • Classification : on regroupe nos individus dans des classes
  • Ascendante : on part du niveau le plus fin (ie des individus)
  • Hiérarchique : la méthode aboutit à la construction d’un arbre

Comment faire : Regrouper les individus les plus proches deux à deux, puis les paquets d’individus deux à deux.

  • Notion de distance pour déterminer les proximités
  • Agrégation des individus puis des groupes d’individus : métrique et hypermétrique

On cherche le nombre optimal de classes d’individus, et pour parvenir à ce nombre, on peut jouer sur plusieurs paramètres :

  • Choix des variables prises en compte : initiales ou composantes principales
  • Choix de la distance : euclidienne, \(\chi^2\), Mahalanobis…
  • Choix de l’hypermétrique : Comment vont être regroupés les individus puis les groupes :
    • centres de gravité les plus proches
    • saut minimum : on agrège les deux groupes pour lesquels la distance entre les deux individus les plus proches est la plus petite
    • diamètre : on agrège les deux groupes pour lesquels la distance entre les deux individus les plus éloignés est la plus petite

Plus de détails sur cette page

En général, on utilise le paramétrage suivant :

  • Réaliser la classification à partir des composantes principales signifiantes (on prend en compte l’essentiel de l’inertie mais on laisse de côté un certain “bruit”, qui correspond aux derniers axes factoriels)
  • Utiliser la distance euclidienne classique
  • Utiliser la méthode de Ward : à chaque étape, agréger les individus (groupes) font perdre le moins d’inertie inter-classes

\(\Rightarrow\) la fonction HCPC du package factominer le fait directement pour vous.

## List of 5
##  $ data.clust:'data.frame':  8403 obs. of  24 variables:
##   ..$ Reading        : Factor w/ 2 levels "Reading_0","Reading_1": 2 2 2 2 2 1 1 2 2 2 ...
##   ..$ Listening music: Factor w/ 2 levels "Listening music_0",..: 2 1 2 1 2 1 2 2 2 2 ...
##   ..$ Cinema         : Factor w/ 2 levels "Cinema_0","Cinema_1": 2 1 1 1 2 1 1 2 2 2 ...
##   ..$ Show           : Factor w/ 2 levels "Show_0","Show_1": 2 1 1 1 2 1 1 2 2 1 ...
##   ..$ Exhibition     : Factor w/ 2 levels "Exhibition_0",..: 2 2 2 2 1 1 1 2 1 2 ...
##   ..$ Computer       : Factor w/ 2 levels "Computer_0","Computer_1": 1 1 1 1 1 1 2 2 2 1 ...
##   ..$ Sport          : Factor w/ 2 levels "Sport_0","Sport_1": 2 2 1 2 1 1 2 1 2 1 ...
##   ..$ Walking        : Factor w/ 2 levels "Walking_0","Walking_1": 2 2 1 1 2 1 1 1 2 1 ...
##   ..$ Travelling     : Factor w/ 2 levels "Travelling_0",..: 2 1 2 2 1 1 1 2 2 1 ...
##   ..$ Playing music  : Factor w/ 2 levels "Playing music_0",..: 1 1 1 1 1 1 1 1 2 2 ...
##   ..$ Collecting     : Factor w/ 2 levels "Collecting_0",..: 1 2 1 1 1 1 1 1 1 1 ...
##   ..$ Volunteering   : Factor w/ 2 levels "Volunteering_0",..: 2 2 1 1 1 1 1 1 1 1 ...
##   ..$ Mechanic       : Factor w/ 2 levels "Mechanic_0","Mechanic_1": 2 2 1 1 1 2 2 1 1 2 ...
##   ..$ Gardening      : Factor w/ 2 levels "Gardening_0",..: 1 2 1 1 1 1 1 1 1 2 ...
##   ..$ Knitting       : Factor w/ 2 levels "Knitting_0","Knitting_1": 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ Cooking        : Factor w/ 2 levels "Cooking_0","Cooking_1": 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ Fishing        : Factor w/ 2 levels "Fishing_0","Fishing_1": 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ TV             : Factor w/ 5 levels "TV_0","TV_1",..: 3 5 5 2 4 4 4 1 2 2 ...
##   ..$ Sex            : Factor w/ 2 levels "F","M": 1 2 1 2 2 2 2 2 1 1 ...
##   ..$ Age            : Factor w/ 8 levels "(25,35]","(35,45]",..: 4 3 1 6 4 3 2 8 2 1 ...
##   ..$ Marital status : Factor w/ 5 levels "Divorcee","Married",..: 2 2 3 2 2 2 2 4 4 4 ...
##   ..$ Profession     : Factor w/ 8 levels "Employee","Foreman",..: 3 6 3 6 1 4 1 6 3 1 ...
##   ..$ nb.activitees  : int [1:8403] 11 9 5 5 6 2 5 7 10 8 ...
##   ..$ clust          : Factor w/ 5 levels "1","2","3","4",..: 5 2 4 4 4 1 4 4 5 4 ...
##  $ desc.var  :List of 5
##   ..$ test.chi2 : num [1:22, 1:2] 0 0 0 0 0 0 0 0 0 0 ...
##   .. ..- attr(*, "dimnames")=List of 2
##   .. .. ..$ : chr [1:22] "Reading" "Listening.music" "Cinema" "Show" ...
##   .. .. ..$ : chr [1:2] "p.value" "df"
##   ..$ category  :List of 5
##   .. ..$ 1: num [1:54, 1:5] 39.8 56 40.4 36.7 39 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:54] "Computer=Computer_0" "Listening.music=Listening music_0" "Cinema=Cinema_0" "Exhibition=Exhibition_0" ...
##   .. .. .. ..$ : chr [1:5] "Cla/Mod" "Mod/Cla" "Global" "p.value" ...
##   .. ..$ 2: num [1:54, 1:5] 68.5 29.8 28.8 26.1 18.1 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:54] "Fishing=Fishing_1" "Mechanic=Mechanic_1" "Gardening=Gardening_1" "Sex=M" ...
##   .. .. .. ..$ : chr [1:5] "Cla/Mod" "Mod/Cla" "Global" "p.value" ...
##   .. ..$ 3: num [1:56, 1:5] 61.2 26.1 28.1 23.4 23.8 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:56] "Knitting=Knitting_1" "Sex=F" "Cooking=Cooking_1" "Sport=Sport_0" ...
##   .. .. .. ..$ : chr [1:5] "Cla/Mod" "Mod/Cla" "Global" "p.value" ...
##   .. ..$ 4: num [1:47, 1:5] 31.2 36.6 26.9 33.7 50.4 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:47] "Gardening=Gardening_0" "Cinema=Cinema_1" "Listening.music=Listening music_1" "Computer=Computer_1" ...
##   .. .. .. ..$ : chr [1:5] "Cla/Mod" "Mod/Cla" "Global" "p.value" ...
##   .. ..$ 5: num [1:57, 1:5] 43.8 53.5 53.8 42.8 41.3 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:57] "Travelling=Travelling_1" "Exhibition=Exhibition_1" "Show=Show_1" "Cinema=Cinema_1" ...
##   .. .. .. ..$ : chr [1:5] "Cla/Mod" "Mod/Cla" "Global" "p.value" ...
##   ..$ quanti.var: num [1, 1:2] 0.763 0
##   .. ..- attr(*, "dimnames")=List of 2
##   .. .. ..$ : chr "nb.activitees"
##   .. .. ..$ : chr [1:2] "Eta2" "P-value"
##   ..$ quanti    :List of 5
##   .. ..$ 1: num [1, 1:6] -63.59 2.97 6.87 1.23 3.38 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr "nb.activitees"
##   .. .. .. ..$ : chr [1:6] "v.test" "Mean in category" "Overall mean" "sd in category" ...
##   .. ..$ 2: NULL
##   .. ..$ 3: NULL
##   .. ..$ 4: num [1, 1:6] 2.14 7.02 6.87 1.54 3.38 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr "nb.activitees"
##   .. .. .. ..$ : chr [1:6] "v.test" "Mean in category" "Overall mean" "sd in category" ...
##   .. ..$ 5: num [1, 1:6] 65.86 11.61 6.87 1.72 3.38 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr "nb.activitees"
##   .. .. .. ..$ : chr [1:6] "v.test" "Mean in category" "Overall mean" "sd in category" ...
##   ..$ call      :List of 4
##   .. ..$ num.var: int 24
##   .. ..$ proba  : num 0.05
##   .. ..$ row.w  : num [1:8403] 1 1 1 1 1 1 1 1 1 1 ...
##   .. ..$ X      :'data.frame':   8403 obs. of  24 variables:
##   .. .. ..$ Reading        : Factor w/ 2 levels "Reading_0","Reading_1": 2 2 2 2 2 1 1 2 2 2 ...
##   .. .. ..$ Listening.music: Factor w/ 2 levels "Listening music_0",..: 2 1 2 1 2 1 2 2 2 2 ...
##   .. .. ..$ Cinema         : Factor w/ 2 levels "Cinema_0","Cinema_1": 2 1 1 1 2 1 1 2 2 2 ...
##   .. .. ..$ Show           : Factor w/ 2 levels "Show_0","Show_1": 2 1 1 1 2 1 1 2 2 1 ...
##   .. .. ..$ Exhibition     : Factor w/ 2 levels "Exhibition_0",..: 2 2 2 2 1 1 1 2 1 2 ...
##   .. .. ..$ Computer       : Factor w/ 2 levels "Computer_0","Computer_1": 1 1 1 1 1 1 2 2 2 1 ...
##   .. .. ..$ Sport          : Factor w/ 2 levels "Sport_0","Sport_1": 2 2 1 2 1 1 2 1 2 1 ...
##   .. .. ..$ Walking        : Factor w/ 2 levels "Walking_0","Walking_1": 2 2 1 1 2 1 1 1 2 1 ...
##   .. .. ..$ Travelling     : Factor w/ 2 levels "Travelling_0",..: 2 1 2 2 1 1 1 2 2 1 ...
##   .. .. ..$ Playing.music  : Factor w/ 2 levels "Playing music_0",..: 1 1 1 1 1 1 1 1 2 2 ...
##   .. .. ..$ Collecting     : Factor w/ 2 levels "Collecting_0",..: 1 2 1 1 1 1 1 1 1 1 ...
##   .. .. ..$ Volunteering   : Factor w/ 2 levels "Volunteering_0",..: 2 2 1 1 1 1 1 1 1 1 ...
##   .. .. ..$ Mechanic       : Factor w/ 2 levels "Mechanic_0","Mechanic_1": 2 2 1 1 1 2 2 1 1 2 ...
##   .. .. ..$ Gardening      : Factor w/ 2 levels "Gardening_0",..: 1 2 1 1 1 1 1 1 1 2 ...
##   .. .. ..$ Knitting       : Factor w/ 2 levels "Knitting_0","Knitting_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. ..$ Cooking        : Factor w/ 2 levels "Cooking_0","Cooking_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. ..$ Fishing        : Factor w/ 2 levels "Fishing_0","Fishing_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. ..$ TV             : Factor w/ 5 levels "TV_0","TV_1",..: 3 5 5 2 4 4 4 1 2 2 ...
##   .. .. ..$ Sex            : Factor w/ 2 levels "F","M": 1 2 1 2 2 2 2 2 1 1 ...
##   .. .. ..$ Age            : Factor w/ 8 levels "(25,35]","(35,45]",..: 4 3 1 6 4 3 2 8 2 1 ...
##   .. .. ..$ Marital.status : Factor w/ 5 levels "Divorcee","Married",..: 2 2 3 2 2 2 2 4 4 4 ...
##   .. .. ..$ Profession     : Factor w/ 8 levels "Employee","Foreman",..: 3 6 3 6 1 4 1 6 3 1 ...
##   .. .. ..$ nb.activitees  : int [1:8403] 11 9 5 5 6 2 5 7 10 8 ...
##   .. .. ..$ clust          : Factor w/ 5 levels "1","2","3","4",..: 5 2 4 4 4 1 4 4 5 4 ...
##   ..- attr(*, "class")= chr [1:2] "catdes" "list"
##  $ desc.axes :List of 3
##   ..$ quanti.var: num [1:4, 1:2] 0.775 0.514 0.473 0.124 0 ...
##   .. ..- attr(*, "dimnames")=List of 2
##   .. .. ..$ : chr [1:4] "Dim.1" "Dim.2" "Dim.3" "Dim.4"
##   .. .. ..$ : chr [1:2] "Eta2" "P-value"
##   ..$ quanti    :List of 5
##   .. ..$ 1: num [1:3, 1:6] 20.0562 -19.0684 -59.7633 0.0912 -0.0982 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:3] "Dim.4" "Dim.2" "Dim.1"
##   .. .. .. ..$ : chr [1:6] "v.test" "Mean in category" "Overall mean" "sd in category" ...
##   .. ..$ 2: num [1:4, 1:6] 48.887 35.121 -8.115 -14.74 0.336 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:4] "Dim.3" "Dim.2" "Dim.1" "Dim.4"
##   .. .. .. ..$ : chr [1:6] "v.test" "Mean in category" "Overall mean" "sd in category" ...
##   .. ..$ 3: num [1:4, 1:6] 38.53 -3.124 -7.159 -48.17 0.266 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:4] "Dim.2" "Dim.4" "Dim.1" "Dim.3"
##   .. .. .. ..$ : chr [1:6] "v.test" "Mean in category" "Overall mean" "sd in category" ...
##   .. ..$ 4: num [1:4, 1:6] 10.564 -3.069 -21.439 -47.23 0.101 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:4] "Dim.1" "Dim.3" "Dim.4" "Dim.2"
##   .. .. .. ..$ : chr [1:6] "v.test" "Mean in category" "Overall mean" "sd in category" ...
##   .. ..$ 5: num [1:3, 1:6] 68.3553 15.4611 3.2677 0.6472 0.0826 ...
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:3] "Dim.1" "Dim.4" "Dim.3"
##   .. .. .. ..$ : chr [1:6] "v.test" "Mean in category" "Overall mean" "sd in category" ...
##   ..$ call      :List of 4
##   .. ..$ num.var: int 5
##   .. ..$ proba  : num 0.05
##   .. ..$ row.w  : num [1:8403] 1 1 1 1 1 1 1 1 1 1 ...
##   .. ..$ X      :'data.frame':   8403 obs. of  5 variables:
##   .. .. ..$ Dim.1: num [1:8403] -0.791 -0.791 -0.791 -0.791 -0.791 ...
##   .. .. ..$ Dim.2: num [1:8403] -0.247 -0.247 -0.247 -0.247 -0.247 ...
##   .. .. ..$ Dim.3: num [1:8403] 0.108 0.108 0.108 0.108 0.108 ...
##   .. .. ..$ Dim.4: num [1:8403] 0.476 0.476 0.476 0.476 0.476 ...
##   .. .. ..$ clust: Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..- attr(*, "class")= chr [1:2] "catdes" "list"
##  $ desc.ind  :List of 2
##   ..$ para:List of 5
##   .. ..$ 1: Named num [1:5] 0.0582 0.0582 0.0681 0.0933 0.0942
##   .. .. ..- attr(*, "names")= chr [1:5] "41006010" "91003910" "82113010" "42015910" ...
##   .. ..$ 2: Named num [1:5] 0.0519 0.094 0.0986 0.1055 0.1124
##   .. .. ..- attr(*, "names")= chr [1:5] "82040110" "93019310" "73031510" "21070410" ...
##   .. ..$ 3: Named num [1:5] 0.101 0.101 0.112 0.126 0.129
##   .. .. ..- attr(*, "names")= chr [1:5] "21071410" "42002410" "52008610" "22012510" ...
##   .. ..$ 4: Named num [1:5] 0.0494 0.0758 0.0798 0.0847 0.0857
##   .. .. ..- attr(*, "names")= chr [1:5] "43035410" "53020410" "26012910" "52011810" ...
##   .. ..$ 5: Named num [1:5] 0.0641 0.1019 0.1124 0.1133 0.1179
##   .. .. ..- attr(*, "names")= chr [1:5] "53003910" "31006410" "93102910" "24015110" ...
##   .. ..- attr(*, "dim")= int 5
##   .. ..- attr(*, "dimnames")=List of 1
##   .. .. ..$ Cluster: chr [1:5] "1" "2" "3" "4" ...
##   .. ..- attr(*, "call")= language by.data.frame(data = tabInd, INDICES = cluster, FUN = select, default.size = nb.par,      method = metric, coord.| __truncated__
##   .. ..- attr(*, "class")= chr "by"
##   ..$ dist:List of 5
##   .. ..$ 1: Named num [1:5] 1.14 1.14 1.13 1.12 1.12
##   .. .. ..- attr(*, "names")= chr [1:5] "11095510" "22033810" "54026710" "93109510" ...
##   .. ..$ 2: Named num [1:5] 1.18 1.14 1.13 1.12 1.12
##   .. .. ..- attr(*, "names")= chr [1:5] "53059510" "22000410" "24042510" "93105810" ...
##   .. ..$ 3: Named num [1:5] 1.2 1.13 1.08 1.03 1.03
##   .. .. ..- attr(*, "names")= chr [1:5] "43026910" "42019410" "74018410" "53023910" ...
##   .. ..$ 4: Named num [1:5] 0.928 0.906 0.9 0.872 0.872
##   .. .. ..- attr(*, "names")= chr [1:5] "93107010" "31040115" "24049910" "24063610" ...
##   .. ..$ 5: Named num [1:5] 1.41 1.39 1.39 1.34 1.33
##   .. .. ..- attr(*, "names")= chr [1:5] "82007410" "82017110" "91048110" "93122510" ...
##   .. ..- attr(*, "dim")= int 5
##   .. ..- attr(*, "dimnames")=List of 1
##   .. .. ..$ Cluster: chr [1:5] "1" "2" "3" "4" ...
##   .. ..- attr(*, "call")= language by.data.frame(data = tabInd, INDICES = cluster, FUN = distinctivness, default.size = nb.par,      method = metric| __truncated__
##   .. ..- attr(*, "class")= chr "by"
##  $ call      :List of 8
##   ..$ t               :List of 6
##   .. ..$ res       :List of 7
##   .. .. ..$ eig       : num [1:21, 1:3] 0.1977 0.0806 0.072 0.0629 0.0585 ...
##   .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. ..$ : chr [1:21] "dim 1" "dim 2" "dim 3" "dim 4" ...
##   .. .. .. .. ..$ : chr [1:3] "eigenvalue" "percentage of variance" "cumulative percentage of variance"
##   .. .. ..$ call      :List of 14
##   .. .. .. ..$ X         :'data.frame':  8403 obs. of  23 variables:
##   .. .. .. .. ..$ Reading        : Factor w/ 2 levels "Reading_0","Reading_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Listening music: Factor w/ 2 levels "Listening music_0",..: 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Cinema         : Factor w/ 2 levels "Cinema_0","Cinema_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Show           : Factor w/ 2 levels "Show_0","Show_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Exhibition     : Factor w/ 2 levels "Exhibition_0",..: 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Computer       : Factor w/ 2 levels "Computer_0","Computer_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Sport          : Factor w/ 2 levels "Sport_0","Sport_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Walking        : Factor w/ 2 levels "Walking_0","Walking_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Travelling     : Factor w/ 2 levels "Travelling_0",..: 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Playing music  : Factor w/ 2 levels "Playing music_0",..: 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Collecting     : Factor w/ 2 levels "Collecting_0",..: 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Volunteering   : Factor w/ 2 levels "Volunteering_0",..: 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Mechanic       : Factor w/ 2 levels "Mechanic_0","Mechanic_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Gardening      : Factor w/ 2 levels "Gardening_0",..: 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Knitting       : Factor w/ 2 levels "Knitting_0","Knitting_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Cooking        : Factor w/ 2 levels "Cooking_0","Cooking_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Fishing        : Factor w/ 2 levels "Fishing_0","Fishing_1": 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ TV             : Factor w/ 5 levels "TV_0","TV_1",..: 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Sex            : Factor w/ 2 levels "F","M": 1 2 1 1 2 2 1 1 1 1 ...
##   .. .. .. .. ..$ Age            : Factor w/ 8 levels "(25,35]","(35,45]",..: 6 1 5 3 7 5 7 5 3 4 ...
##   .. .. .. .. ..$ Marital status : Factor w/ 5 levels "Divorcee","Married",..: 3 4 5 2 5 2 5 5 1 2 ...
##   .. .. .. .. ..$ Profession     : Factor w/ 8 levels "Employee","Foreman",..: 3 6 1 4 6 8 6 8 1 6 ...
##   .. .. .. .. ..$ nb.activitees  : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. ..$ marge.col : Named num [1:39] 0.0182 0.0373 0.0162 0.0393 0.0333 ...
##   .. .. .. .. ..- attr(*, "names")= chr [1:39] "Reading_0" "Reading_1" "Listening music_0" "Listening music_1" ...
##   .. .. .. ..$ marge.row : Named num [1:8403] 0.000119 0.000119 0.000119 0.000119 0.000119 ...
##   .. .. .. .. ..- attr(*, "names")= chr [1:8403] "11000210" "11000410" "11000610" "11000710" ...
##   .. .. .. ..$ ncp       : num 4
##   .. .. .. ..$ row.w     : num [1:8403] 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. ..$ excl      : NULL
##   .. .. .. ..$ call      : language MCA(X = hobbies, ncp = 4, quanti.sup = 23, quali.sup = 19:22, graph = F)
##   .. .. .. ..$ Xtot      :'data.frame':  8403 obs. of  62 variables:
##   .. .. .. .. ..$ Reading_0        : int [1:8403] 0 0 0 0 0 1 1 0 0 0 ...
##   .. .. .. .. ..$ Reading_1        : int [1:8403] 1 1 1 1 1 0 0 1 1 1 ...
##   .. .. .. .. ..$ Listening music_0: int [1:8403] 0 1 0 1 0 1 0 0 0 0 ...
##   .. .. .. .. ..$ Listening music_1: int [1:8403] 1 0 1 0 1 0 1 1 1 1 ...
##   .. .. .. .. ..$ Cinema_0         : int [1:8403] 0 1 1 1 0 1 1 0 0 0 ...
##   .. .. .. .. ..$ Cinema_1         : int [1:8403] 1 0 0 0 1 0 0 1 1 1 ...
##   .. .. .. .. ..$ Show_0           : int [1:8403] 0 1 1 1 0 1 1 0 0 1 ...
##   .. .. .. .. ..$ Show_1           : int [1:8403] 1 0 0 0 1 0 0 1 1 0 ...
##   .. .. .. .. ..$ Exhibition_0     : int [1:8403] 0 0 0 0 1 1 1 0 1 0 ...
##   .. .. .. .. ..$ Exhibition_1     : int [1:8403] 1 1 1 1 0 0 0 1 0 1 ...
##   .. .. .. .. ..$ Computer_0       : int [1:8403] 1 1 1 1 1 1 0 0 0 1 ...
##   .. .. .. .. ..$ Computer_1       : int [1:8403] 0 0 0 0 0 0 1 1 1 0 ...
##   .. .. .. .. ..$ Sport_0          : int [1:8403] 0 0 1 0 1 1 0 1 0 1 ...
##   .. .. .. .. ..$ Sport_1          : int [1:8403] 1 1 0 1 0 0 1 0 1 0 ...
##   .. .. .. .. ..$ Walking_0        : int [1:8403] 0 0 1 1 0 1 1 1 0 1 ...
##   .. .. .. .. ..$ Walking_1        : int [1:8403] 1 1 0 0 1 0 0 0 1 0 ...
##   .. .. .. .. ..$ Travelling_0     : int [1:8403] 0 1 0 0 1 1 1 0 0 1 ...
##   .. .. .. .. ..$ Travelling_1     : int [1:8403] 1 0 1 1 0 0 0 1 1 0 ...
##   .. .. .. .. ..$ Playing music_0  : int [1:8403] 1 1 1 1 1 1 1 1 0 0 ...
##   .. .. .. .. ..$ Playing music_1  : int [1:8403] 0 0 0 0 0 0 0 0 1 1 ...
##   .. .. .. .. ..$ Collecting_0     : int [1:8403] 1 0 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Collecting_1     : int [1:8403] 0 1 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Volunteering_0   : int [1:8403] 0 0 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Volunteering_1   : int [1:8403] 1 1 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Mechanic_0       : int [1:8403] 0 0 1 1 1 0 0 1 1 0 ...
##   .. .. .. .. ..$ Mechanic_1       : int [1:8403] 1 1 0 0 0 1 1 0 0 1 ...
##   .. .. .. .. ..$ Gardening_0      : int [1:8403] 1 0 1 1 1 1 1 1 1 0 ...
##   .. .. .. .. ..$ Gardening_1      : int [1:8403] 0 1 0 0 0 0 0 0 0 1 ...
##   .. .. .. .. ..$ Knitting_0       : int [1:8403] 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Knitting_1       : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Cooking_0        : int [1:8403] 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Cooking_1        : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Fishing_0        : int [1:8403] 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. .. .. ..$ Fishing_1        : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ TV_0             : int [1:8403] 0 0 0 0 0 0 0 1 0 0 ...
##   .. .. .. .. ..$ TV_1             : int [1:8403] 0 0 0 1 0 0 0 0 1 1 ...
##   .. .. .. .. ..$ TV_2             : int [1:8403] 1 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ TV_3             : int [1:8403] 0 0 0 0 1 1 1 0 0 0 ...
##   .. .. .. .. ..$ TV_4             : int [1:8403] 0 1 1 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ F                : int [1:8403] 1 0 1 0 0 0 0 0 1 1 ...
##   .. .. .. .. ..$ M                : int [1:8403] 0 1 0 1 1 1 1 1 0 0 ...
##   .. .. .. .. ..$ (25,35]          : int [1:8403] 0 0 1 0 0 0 0 0 0 1 ...
##   .. .. .. .. ..$ (35,45]          : int [1:8403] 0 0 0 0 0 0 1 0 1 0 ...
##   .. .. .. .. ..$ (45,55]          : int [1:8403] 0 1 0 0 0 1 0 0 0 0 ...
##   .. .. .. .. ..$ (55,65]          : int [1:8403] 1 0 0 0 1 0 0 0 0 0 ...
##   .. .. .. .. ..$ (65,75]          : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ (75,85]          : int [1:8403] 0 0 0 1 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ (85,100]         : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ [15,25]          : int [1:8403] 0 0 0 0 0 0 0 1 0 0 ...
##   .. .. .. .. ..$ Divorcee         : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Married          : int [1:8403] 1 1 0 1 1 1 1 0 0 0 ...
##   .. .. .. .. ..$ Remarried        : int [1:8403] 0 0 1 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Single           : int [1:8403] 0 0 0 0 0 0 0 1 1 1 ...
##   .. .. .. .. ..$ Widower          : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Employee         : int [1:8403] 0 0 0 0 1 0 1 0 0 1 ...
##   .. .. .. .. ..$ Foreman          : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Management       : int [1:8403] 1 0 1 0 0 0 0 0 1 0 ...
##   .. .. .. .. ..$ Manual labourer  : int [1:8403] 0 0 0 0 0 1 0 0 0 0 ...
##   .. .. .. .. ..$ Other            : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Profession.NA    : int [1:8403] 0 1 0 1 0 0 0 1 0 0 ...
##   .. .. .. .. ..$ Technician       : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. .. ..$ Unskilled worker : int [1:8403] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. .. ..$ N         : num 151254
##   .. .. .. ..$ col.sup   : int [1:23] 40 41 42 43 44 45 46 47 48 49 ...
##   .. .. .. ..$ quali     : int [1:18] 1 2 3 4 5 6 7 8 9 10 ...
##   .. .. .. ..$ quali.sup : int [1:4] 19 20 21 22
##   .. .. .. ..$ quanti.sup: num 23
##   .. .. .. ..$ row.w.init: num [1:8403] 1 1 1 1 1 1 1 1 1 1 ...
##   .. .. ..$ ind       :List of 3
##   .. .. .. ..$ coord  :'data.frame': 8403 obs. of  4 variables:
##   .. .. .. .. ..$ Dim 1: num [1:8403] -0.791 -0.791 -0.791 -0.791 -0.791 ...
##   .. .. .. .. ..$ Dim 2: num [1:8403] -0.247 -0.247 -0.247 -0.247 -0.247 ...
##   .. .. .. .. ..$ Dim 3: num [1:8403] 0.108 0.108 0.108 0.108 0.108 ...
##   .. .. .. .. ..$ Dim 4: num [1:8403] 0.476 0.476 0.476 0.476 0.476 ...
##   .. .. .. ..$ contrib: num [1:8403, 1:4] 2.68e-02 1.17e-03 1.45e-03 6.99e-04 2.78e-05 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:8403] "11000210" "11000410" "11000610" "11000710" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. .. ..$ cos2   : num [1:8403, 1:4] 0.335743 0.011164 0.031778 0.010507 0.000558 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:8403] "11000210" "11000410" "11000610" "11000710" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. ..$ var       :List of 5
##   .. .. .. ..$ coord  : num [1:39, 1:4] -0.699 0.341 -0.817 0.337 -0.509 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:39] "Reading_0" "Reading_1" "Listening music_0" "Listening music_1" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. .. ..$ contrib: num [1:39, 1:4] 4.5 2.2 5.48 2.26 4.37 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:39] "Reading_0" "Reading_1" "Listening music_0" "Listening music_1" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. .. ..$ cos2   : num [1:39, 1:4] 0.239 0.239 0.275 0.275 0.389 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:39] "Reading_0" "Reading_1" "Listening music_0" "Listening music_1" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. .. ..$ v.test : num [1:39, 1:4] -44.8 44.8 -48.1 48.1 -57.2 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:39] "Reading_0" "Reading_1" "Listening music_0" "Listening music_1" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. .. ..$ eta2   : num [1:18, 1:4] 0.239 0.275 0.389 0.383 0.399 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:18] "Reading" "Listening music" "Cinema" "Show" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. ..$ svd       :List of 3
##   .. .. .. ..$ vs: num [1:39] 0.445 0.284 0.268 0.251 0.242 ...
##   .. .. .. ..$ U : num [1:8403, 1:4] 1.4999 0.3142 -0.3492 -0.2424 -0.0484 ...
##   .. .. .. ..$ V : num [1:39, 1:4] -1.572 0.768 -1.837 0.759 -1.145 ...
##   .. .. ..$ quali.sup :List of 4
##   .. .. .. ..$ coord : num [1:23, 1:4] 0.0176 -0.0214 0.2674 0.201 0.0219 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:23] "F" "M" "(25,35]" "(35,45]" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. .. ..$ cos2  : num [1:23, 1:4] 0.000377 0.000377 0.013109 0.009838 0.000135 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:23] "F" "M" "(25,35]" "(35,45]" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. .. ..$ v.test: num [1:23, 1:4] 1.78 -1.78 10.49 9.09 1.06 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:23] "F" "M" "(25,35]" "(35,45]" ...
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. .. ..$ eta2  : num [1:4, 1:4] 0.000377 0.097479 0.045662 0.128368 0.002153 ...
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr [1:4] "Sex" "Age" "Marital status" "Profession"
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. ..$ quanti.sup:List of 1
##   .. .. .. ..$ coord: num [1, 1:4] 0.9753 0.198 0.0126 -0.0581
##   .. .. .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. .. .. ..$ : chr "nb.activitees"
##   .. .. .. .. .. ..$ : chr [1:4] "Dim 1" "Dim 2" "Dim 3" "Dim 4"
##   .. .. ..- attr(*, "class")= chr [1:2] "MCA" "list"
##   .. ..$ tree      :List of 7
##   .. .. ..$ merge      : int [1:8402, 1:2] -1 -3 -4 -5 -6 -7 -8 -9 -10 -11 ...
##   .. .. ..$ height     : num [1:8402] 0 0 0 0 0 0 0 0 0 0 ...
##   .. .. ..$ order      : int [1:8403] 6129 6280 5758 6048 6405 6582 6249 6652 6802 7049 ...
##   .. .. ..$ labels     : chr [1:8403] "11023410" "22031210" "22032610" "23010810" ...
##   .. .. ..$ method     : chr "ward"
##   .. .. ..$ call       : language flashClust::hclust(d = dissi, method = method, members = weight)
##   .. .. ..$ dist.method: chr "euclidean"
##   .. .. ..- attr(*, "class")= chr "hclust"
##   .. ..$ nb.clust  : num 3
##   .. ..$ within    : num [1:8402] 0.413 0.294 0.258 0.228 0.209 ...
##   .. ..$ inert.gain: num [1:8402] 0.1191 0.0357 0.0301 0.0189 0.0181 ...
##   .. ..$ quot      : num [1:8] 0.879 0.884 0.917 0.914 0.938 ...
##   ..$ min             : num 3
##   ..$ max             : num 10
##   ..$ X               :'data.frame': 8403 obs. of  5 variables:
##   .. ..$ Dim 1: num [1:8403] -0.791 -0.791 -0.791 -0.791 -0.791 ...
##   .. ..$ Dim 2: num [1:8403] -0.247 -0.247 -0.247 -0.247 -0.247 ...
##   .. ..$ Dim 3: num [1:8403] 0.108 0.108 0.108 0.108 0.108 ...
##   .. ..$ Dim 4: num [1:8403] 0.476 0.476 0.476 0.476 0.476 ...
##   .. ..$ clust: Factor w/ 5 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ bw.before.consol: num 0.204
##   ..$ bw.after.consol : num 0.237
##   ..$ vec             : logi FALSE
##   ..$ call            : language HCPC(res = acm, nb.clust = 5, graph = F)
##  - attr(*, "class")= chr "HCPC"

7.2.1 Détermination du nombre de classes

Pour déterminer le nombre optimal de classes, on regarde la perte d’inertie inter-classes (pour ça, il faut lancer une première fois la commande avec un nombre arbitraire de classes). En effet, on part d’une situation où il n’y a que de l’inertie inter-classes (chaque classe comprenant un seul individu, il n’y a pas d’inertie intra-classe). Au fur et à mesure des regroupements, on va donc perdre en inertie inter-classes, jusqu’à la dernière étape où il y a une classe avec tous les individus et donc plus d’inertie inter. Le but du jeu consiste à “stopper” l’aggrégation avant de perdre une forte quantité d’inertie inter-classe. On s’intéresse au dernières étapes pour ne pas alourdir le graphique (et on prendra un nombre de classe inférieur à 20 en général, sinon, ce n’est pas très opérationnel…). Ce diagramme ressemble très fortement à l’éboulis des valeurs propres, et on cherche à peu près la même chose (un saut).

Autre représentation : le dendogramme représente les étapes d’agrégation. La auteur des branches représente la perte d’inertie inter-classe (ou le gain d’inertie intra)

7.2.2 Description des classes

Une fois que l’on a déterminé le nombre de classes, il reste à les décrire. Premier outil : le tableau croisé pour voir la taille de chacun.

## 
##    1    2    3    4    5 
## 2234 1290 1410 1722 1747
  • cla/mod indique quelle part (pourcentage) de tous les individus présentant cette modalité se retrouve dans cette classe
  • mod/cla indique quelle part (pourcentage) de tous les individus de la classe présentent cette modalité.
  • Les parangons sont les individus les plus représentatifs de la classe

Visualisation du dendogrades classes sur les axes factoriels

7.2.3 Quelques conseils pratiques

Le but d’un classification est d’obtenir des groupes d’individus qui “parlent” (c’est un outils de communication puissant) ; l’application des méthodes à la lettre peut ne pas aboutir à un tel résultat. On peut alors jouer sur différents paramètres :

  • Les variables mobilisées
  • Le nombre de classes
  • La distance
  • La méthode d’agrégation
  • Utiliser une méthode non hiérarchique (exemple : kmeans) \(\rightarrow\) pour “consolider” la CAH avec cette méthode (permet de minimiser la variance intra)

Remarque importante : l’algorithme est très coûteux et est très lent quand le nombre d’individus est important. On peut alors réduire le nombre d’individus initial en procédant au préalable à une classification avec kmeans. La fonction HCPC permet de le faire avec le paramètre kk=.

Il faut ensuite donner un nom aux classes (pas uniquement les décrire) : attention aux termes utilisés !

7.3 Exercice

Reprendre la base de données sur les iris et réaliser une classification des 150 fleurs

  • Avec kmeans
  • Avec une CAH
  • Que peut-on dire des résultats et leur lien avec la variable Species ?

On compare à la vraie classe. Conclusion : la nature est mal faite…