L'ACP, ou Analyse en Composantes Principales, est une méthode d'exploration de données qui consiste à réduire la dimensionnalité du problème pour en extraire l'essentiel. Par une projection dans un espace plus petit, on réduit le nombre de variables, et si on réduit suffisamment on peut en faire un outil de diagnostic graphique. Comme c'est une projection, il est important de comprendre qu'on perd de l'information dans le processus, mais cela permet d'interpréter plus facilement les données.
Table des matières :
La méthode
En pratique, on part d'un tableau avec N lignes représentant les individus mesurés - par exemple 1000 souris - et P colonnes représentant les variables mesurées - par exemple la taille, le poids, l'âge etc. des souris. L'idée, c'est qu'il est facile de représenter sur un graphique une situation à deux variables : la taille sur l'axe des x, le poids sur l'axe des y, un point par souris. On pourrait imaginer ajouter un 3ème axe pour l'âge et visualiser les points dans un "cube" en 3D. Mais à partir de 4 variables, la visualisation devient impossible. Pour réduire la dimension, on va essayer de ne garder que l'essentiel. L'ACP va transformer le tableau pour qu'il ne compte plus que deux (nouvelles) colonnes tout en conservant un maximum d'information.
Sans entrer dans les détails, la transformation implique d'abord une rotation des axes de coordonnées : le premier axe suivra la direction la plus "allongée" (imaginez un poisson ; l'axe va de la tête à la queue), le second une direction perpendiculaire (du ventre vers le dos), le troisième perpendiculaire aux deux premiers (l'épaisseur du poisson), etc. Cela sert à maximiser la variabilité des points le long du premier axe, puis la variabilité du reste le long du second, etc. de sorte qu'il n'y ait presque plus de variation le long des axes suivants. Ces nouveaux axes s'appellent composantes principales ; ce sont P vecteurs de taille P. Mathématiquement, ce sont les vecteurs propres de la matrice de covariance de notre table, et on fait un changement de base.

Axes du repère d'origine (image d'origine : wikimedia.org)
Ensuite on fait une sélection des composantes : plus on en garde, plus complètement on peut recomposer l'objet (si on n'a gardé que les deux premières composantes du poisson, on ne peut reconstruire qu'un poisson tout plat).
L'important dans tout ca, c'est que si les deux premières composantes cumulent une grande portion de la variabilité totale, on peut ignorer les autres et les opposer dans un graphique.
Un exemple avec R
Ici nous partirons du jeu de données "iris" déjà inclus dans la plupart des distributions de R. La table ressemble à ça :
1 2 3 4 5 6 7 8 |
> head(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa |
Il y a 150 individus et 4 dimensions/variables. Les 150 sont groupés en 3 espèces setosa, versicolor et virginica. Ce qu'on voudrait savoir, c'est s'il y a une différence importante entre les espèces, et s'il y en a une, quelles sont les variables qui contribuent le plus à expliquer cette différence.
Il y a deux commandes à choix pour faire l'ACP en R (j'expliquerai plus tard pourquoi) : prcomp et princomp. Ici je vais utiliser prcomp ; avec princomp le résultat est presque le même, et l'utilisation est identique aux noms des attributs près.
1 |
pca = prcomp(iris[,1:4]) |
Les composantes principales (PCx, pour "Principal Component") sont les colonnes de pca$rotation :
1 2 3 4 5 6 |
> pca$rotation PC1 PC2 PC3 PC4 Sepal.Length 0.36138659 -0.65658877 0.58202985 0.3154872 Sepal.Width -0.08452251 -0.73016143 -0.59791083 -0.3197231 Petal.Length 0.85667061 0.17337266 -0.07623608 -0.4798390 Petal.Width 0.35828920 0.07548102 -0.54583143 0.7536574 |
On voit par exemple que l'axe "PC1" est une combinaison de 0.86 x Petal.Length, 0.36 x de Sepal.Length et Petal.Width, et -0.08 x Sepal.Width - c'est-à-dire que la direction de la PC1 est à peu près alignée avec celle de Petal.Length et quasi perpendiculaire à celle de Sepal.Width. On appelle aussi ces nombres "loadings".
pca$sdev donne la fraction d'information (sdev="standard deviation") contenue dans chacune des composantes :
1 2 3 4 5 6 7 8 |
> pca$sdev # Les écarts-types "bruts" [1] 2.0562689 0.4926162 0.2796596 0.1543862 > 100 * pca$sdev^2 / sum(pca$sdev^2) # Proportion de variance [1] 92.4618723 5.3066483 1.7102610 0.5212184 # de chaque composante > sum(100 * (pca$sdev^2)[1:2] / sum(pca$sdev^2)) # Variance totale de [1] 97.76852 # PC1 + PC2, en % |
Ainsi les deux premières composantes à elles seules contiennent 97.77% de l'information, il est donc raisonnable de garder seulement deux variables en ne perdant que 2.33% d'info, ou même une seule (ce que je ferais en pratique, mais ici on en gardera deux pour plus de généralité). On peut aussi rendre compte de ces proportions avec un bar plot des variances :
1 |
plot(pca) |
Je ne vous cache pas qu'on peut en produire un plus joli soi-même.
Les données transformées par rotation sont dans pca$x ; chaque colonne est la projection des points sur l'une des composantes principales. Ainsi si on garde seulement les deux premières, on a la projection des points dans le plan PC1-PC2 et on peut en faire un graphique qu'on appelle "biplot" :
1 |
plot(pca$x[,1:2], col=iris[,5]) |
L'axe horizontal est notre PC1, l'axe vertical la PC2. En coloriant les points selon l'espèce de plante, on voit que la PC1 les distingue presque parfaitement :
En fait on a vu que la composante 2 n'est pas très utile, et on pourrait très bien choisir de réduire encore la dimension et séparer nos points selon un seul axe :
1 |
plot(pca$x[,1], rep(0,nrow(iris)), col=iris[,5]) |
L'interprétation ensuite est la suivante : d'abord l'espèce setosa (à gauche) est nettement plus reconnaissable que les deux autres entre elles. Ensuite, comme c'est la composante 1 qui sépare les espèces, on regarde de quoi elle est faite. On avait vu qu'elle était composée principalement de Petal.Length ; on en déduit que c'est principalement à la longueur des pétales qu'on reconnaît les espèces. A vrai dire l'interprétation est souvent difficile, et on se contente alors de remarquer que les groupes sont bien différenciés/groupés comme on l'attend.
Il existe aussi une commande R qui fait le biplot toute seule mais... chacun ses goûts. Les flèches qui apparaissent sur le graphique sont les anciens axes de coordonnées (il y a aura donc P flèches - et on ne peut pas en réduire le nombre, ce qui peut devenir très lourd). Il est aussi centré en zéro et réduit (ce n'est pas important pour l'interprétation).
1 |
biplot(pca) |
Autres applications
On peut se servir de l'ACP par exemple en RNA-seq pour regarder si l'expression globale des gènes est très différente d'un groupe de patients à un autre, ou si les réplicats de l'expérience sont suffisamment semblables - dans le cas contraire ça permet d'éliminer les mauvais échantillons et rendre l'analyse plus robuste. On considère alors ces fameuses tables avec un gène par ligne et une colonne par échantillon, indiquant dans chaque case l'expression d'un gène dans un échantillon particulier.
De façon similaire, on peut mesurer la présence ou l'absence de chaque variation du génome (SNP) de 3000 Européens, et comparer le graphe de l'ACP à la carte de la région, c'est plutôt spectaculaire. C'est aussi un bon exemple de cas où l'interprétation découle directement de la disposition des points et pas du contenu des composantes principales :
Dans des contextes différents, on peut l'appliquer pour la compression d'images, la reconnaissance de mouvements, etc.
Finalement, c'est aussi un moyen de trouver la "meilleure" droite passant par un nuage de points, un peu comme on le fait en régression linéaire, avec l'avantage que le résultat est le même si on échange les axes (ce n'est pas le cas de la régression !). Cette droite passe par le centre du nuage dans la direction du vecteur PC1.
En bonus, le code pour ce dernier graphique :
1 2 3 4 5 6 7 8 9 10 |
library(MASS) x <- mvrnorm(1000, c(0,0), matrix(c(5,1,3,2), 2,2)) plot(x, xlim=c(-8,8), ylim=c(-8,8), xlab="X", ylab="Y") pca = prcomp(x) r = pca$rotation abline(0, r[2,1]/r[1,1], col="red") lin.model = lm(x[,1] ~ x[,2]) abline(0, lin.model$coefficients[2], col="blue") lin.model = lm(x[,2] ~ x[,1]) abline(0, lin.model$coefficients[2], col="blue") |
Prcomp et princomp
La différence entre ces deux commandes R se trouve dans la méthode mathématique utilisée. La décomposition en composantes principales peut se faire soit par SVD (Décomposition en Valeurs Singulières), soit par recherche des vecteurs propres de la matrice de covariance. Ainsi, on remarque que prcomp (SVD) est plus rapide, et même que si on essaye avec la matrice transposée (voir plus bas), princomp va se plaindre car il n'existe pas suffisamment de vecteurs propres :
1 2 3 |
> princomp(t(iris[,1:4])) Error in princomp.default(t(iris[,1:4])) : 'princomp' can only be used with more units than variables |
alors que pour prcomp tout va très bien :
1 |
prcomp(t(iris[,1:4])) |
De plus, le calcul de la SVD est plus stable numériquement. Les noms des attributs sont aussi différents. Voici la correspondance si on y tient :
prcomp -> princomp
pca$x -> pca$scores
pca$rotation -> pca$loadings[,1:4]
pca$sdev -> pca$sdev
Pour aller plus loin
- On peut aussi toujours s'intéresser au problème inverse en transposant la table des données. Par exemple, si on a une table avec une ligne par gène et une colonne par condition expérimentale, l'ACP telle que nous l'avons présentée ressortira un graphique avec un point par gène, et on espère voir des "clusters" de gènes en fonction des échantillons. Si on transpose la table pour avoir une ligne par condition et une colonne par gène, on obtiendra un graphique avec un point par condition, et on espère voir les réplicats ensemble et les malades bien séparés des contrôles.
- Lorsque les variables sont, comme dans l'exemple "iris", du même type (des longueurs, en cm), tout va bien. Mais si on commence à mélanger des tonnes et des microns, alors les échelles seront différentes et l'ACP sera biaisée en faveur des nombres les plus grands. Pour y remédier, on peut choisir de normaliser les variables avec l'option "scale=TRUE", ce qui divisera chaque colonne par sa variance. Si cette normalisation s'avère trop forte (c'est le cas avec les expressions de gènes), on peut simplement appliquer un logarithme.
- La théorie part du principe que les variables initiales sont indépendantes (axes orthogonaux). En pratique on ignore joyeusement cette contrainte, comme par exemple dans le cas de l'expression des gènes. Un inconvénient, c'est que les composantes principales contiennent un mélange d'un peu toutes les variables à la fois, rendant l'interprétation difficile. Il existe une adaptation de l'ACP pour variables corrélées qu'on appelle "ACP éparse" ("sparse PCA"), exploitant la technique du lasso en interprétant l'ACP comme un problème de régression. Alors un grand nombre de coefficients des composantes principales deviennent nuls et on peut plus facilement extraire les variables significatives. Pour plus de détails, voir H. Zou, T. Hastie, R. Tibshirani, "Sparse principal component analysis", 2004. Les auteurs ont implémenté la méthode dans le package R elasticnet.
- Il existe des packages R comprenant des fonctions pour une étude plus poussée de l'ACP, d'ailleurs développés par des Français : FactomineR, Ade4 and amap. Je ne les ai pas testés, mais je vous invite à regarder par exemple ce lien.
Merci à Hautbit, Maxi_Zu et Estel pour leur relecture.
Jonathan Sobel
mars 4, 2015 à 6:08
Super Article!
J'ai adoré L'image du poisson. C'est vraiment clair comme explication et ça donne une bonne intuition de la projection.
Ciao.
Julien Delafontaine
mars 4, 2015 à 10:21
Merci ! J'ai pas trouvé de poisson en 4D sur le web malheureusement, mais je compte sur l'imagination du lecteur pour étendre l'exemple aux dimensions supérieures.
ibliss
mars 5, 2015 à 1:51
Félicitations ! Très bon billet.
Julien Delafontaine
mars 15, 2015 à 9:56
Merci !
Nasser
mars 10, 2015 à 5:56
J'adore! ça parait un peu bête mais quelles sont les avantages d'un tableur par rapport à R?
Julien Delafontaine
mars 10, 2015 à 6:36
Le formatage des documents. R sert a faire des analyses sophistiquees et des figures que le tableur ne connait pas, mais pas des jolies tables avec des bordures colorees et des enluminures.
Nasser
mars 11, 2015 à 9:53
merci bien
aurelien
mars 18, 2015 à 4:03
Bonjour Pour quoi ne pas avoir citer la commande PCA(matrice)en plus des commandes prcomp et princomp. la commande PCA possède elle des inconvénients qui la rende inutile?
Julien Delafontaine
mars 18, 2015 à 6:04
Bonjour. Chez moi (R version 3.1.2),
> PCA
Erreur : objet 'PCA' introuvable
> PCA(iris[,1:4])
Erreur : impossible de trouver la fonction "PCA"
Donc la commande "PCA" doit venir d'un package externe. On peut savoir d'ou elle vient en entrant son som dans la console, comme prcomp qui vient de :
> prcomp
function (x, ...)
UseMethod("prcomp")
Julien Delafontaine
mars 18, 2015 à 6:05
hmm les "<>" sont interpretees comme des balises html... mais je voulais dire "vient de
stats
", et si on tape "prcomp", ca affiche aussibytecode: 0x7f96f56c52e8
environment: namespace:stats
Romz
avril 11, 2015 à 1:54
La commande PCA fait partie du package "FactoMineR". Elle est très pratique car très complète (calcule les % d'explication des différentes composantes et superposition des axes des descripteurs pour mieux comprendre la séparation).
aurelien
avril 16, 2015 à 9:32
Merci pour ce post, très informatif. Serait il possible de nous expliquer aussi simplement la différence entre ACP et l'analyse en coordonnées principales, implementée en R par
cmdscale()
?Merci d'avance.
Julien Delafontaine
avril 16, 2015 à 7:23
L'analyse en coordonnees principales calcule les vecteurs propres d'une matrice de ressemblance, alors que l'ACP utilise la matrice de covariance (/correlation). Une matrice de ressemblance contient toutes les distances (euclidiennes en principe) entre paires d'elements.
L'ACoP est donc une technique de projection similaire mais dans un contexte ou la notion de distance entre les variables a plus de sens que leur covariance.
Il existe encore une variante appelee MDS ("multi-dimensional" scaling).
Emilie
novembre 4, 2015 à 5:24
Bonjour,
Pourriez-vous expliquer la différence entre une ACP et une MDS? Ainsi qu'entre une MDS métrique et non-métrique?
Merci d'avance pour votre réponse.
Julien Delafontaine
novembre 5, 2015 à 7:19
Le MDS cherche aussi a projeter les points dans un espace de moindre dimension, mais en essayant de conserver au maximum les distances entre les points, alors que la contrainte de la PCA est de minimiser la variance le long de chaque axe.
En fait la PCoA est la variante "classique" de MDS. Les differents MDS se distinguent par la facon de definir la matrice de dissimilarites (p.ex. distances entre les points pour la PCoA). Le MDS est non-metrique si on opere une transformation lineaire des entrees de la matrice de dissimilarites. Je n'en sais pas plus malheureusement.
DieHuda
juillet 11, 2015 à 8:30
Merci très bon article
***
octobre 30, 2015 à 11:27
Bonjour,
J'aurais voulu savoir pour le premier exemple, qu'est-ce qu'on peut faire avec une seule composante principale ? En termes de représentation graphique et/ou amélioration du modèle si nécessaire ?
Je me trouve dans un cas similaire et peine à interpréter un tel résultat...
J'espère que vous pourrez m'aider !
Merci
Julien Delafontaine
novembre 3, 2015 à 9:20
D'abord ca peut servir a classifier les points, si le long de l'axe de la CP on voit des groupe des points, plus particulierement un groupe avant le 0 et un groupe apres. Dans l'exemple c'est encore plus facile, car on voit tout de suite en ajoutant des couleurs que la CP separe bien les trois groupes de plantes.
On peut essayer d'expliquer la difference entre les membres des differents groupes par les variables qui construisent la CP. Si par exemple le vecteur de la CP s'ecrit (0,0,-0.02,18,0,0), on va dire que c'est principalement la variable 4 qui est determinante pour classifier les points (mais en principe c'est une combinaison de plusieurs ; il faut ordonner les composantes de la CP pour mieux les voir. S'il y en a trop on ne peux rien en faire).
SY
novembre 4, 2015 à 12:07
Bonjour,
J'aimerais savoir quel package vous avez utilisé pour faire l'ACP.
Merci d'avance
Julien Delafontaine
novembre 4, 2015 à 5:53
Il n'y a pas besoin de package. Essayez juste les commandes indiquees dans R.
SY
novembre 4, 2015 à 7:05
Merci beaucoup!
J'aimerai aussi savoir s'il existe d'autres commandes comme celles là pour effectuer l'Analyse Factorielle des Correspondances et l'Analyse des Correspondances Multiples et la Classification?
Julien Delafontaine
novembre 5, 2015 à 7:07
R est fait pour ca, donc oui. Il existe de nombreux livres et tutoriels en ligne. La litterature - comme la doc de R d'ailleurs - est souvent en anglais par contre, par exemple Classification s'appelle Clustering.
SY
novembre 5, 2015 à 12:40
Merci beaucoup!
C'est noté.
louis
décembre 8, 2015 à 3:44
Super Article!
Merci pour ce post, très informatif!
Quentin.Etz
avril 27, 2016 à 3:24
Bonjour, je ne comprend pas très bien comment se font les couleurs sur un graphique R. J'ai bien compris votre exemple en colorant les points associés aux différentes types de plantes, mais si j'essaye avec cette ligne de code par exemple : plot(pca$x[,1:2],col=iris[,3]), j'obtiens un graphique avec 5 couleurs différentes, et la je ne comprend plus très bien car ma colonne 3 dans "iris" est une succession de valeurs numériques bien distinctes, et non plus 3 chaines de caractères différentes comme dans la colonne 5. Pourriez-vous m'expliquer si ça ne vous dérange pas ? Merci d'avance de votre réponse.
Julien Delafontaine
avril 28, 2016 à 5:43
Oui, c'est iris[,5]. Si on tape "iris" on voit pourquoi.
Quentin.Etz
avril 29, 2016 à 2:42
Excusez moi mais je n'ai toujours pas compris pour mon exemple avec iris[,3] (exemple que j'ai pris au hasard). Pour iris[,5], on a 3 chaines de caractère différentes, donc je comprend que R fait un graphique avec 3 couleurs différentes pour les distinguer.
Je voulais aussi vous demander à quoi correspondent les échelles sur le graphique représentant PC2=f(PC1) (Echelle variant de -3 à 4 pour la PC1 et de -1 à 1 pour la PC2)
Cordialement
Julien Delafontaine
mai 1, 2016 à 8:20
R s'attend à un facteur pour les colonnes, donc il faut passer col=as.factor(iris[,3]). C'est un très bon exemple de pourquoi R est un très mauvais langage (fait n'importe quoi quand on lui passe un truc faux, au lieu de générer une erreur).
Pour les échelles, si par exemple PC1 = (0,3,1), alors 1 unité selon cet axe vaut 0*x1 + 3*x2 + 1*x3, où x1, x2, x3 sont les variables d'origine.
Quentin.Etz
mai 2, 2016 à 9:07
Merci de votre réponse.
Juste une précision, dans notre exemple, on a bien PC1 = (0.36,-0.08,0.86,0.36) si j'ai bien compris ?
meryem
mai 6, 2016 à 10:49
bonjour j'ai effectué une ACP avec la fonction PCA de FactoMineR et je veux savoir quelle est la fonction analogue a $rotation dans ce package
lounes
mai 6, 2016 à 10:05
Bonjour,
Je voulais juste faire une remarque si vous permettez.
Vous dites que les colonnes de pca$x sont la projection des points sur l'une des composantes principales. C'est pas plutot sur les axes principaux (les vecteurs propres)?
La projection sur les composantes principales est faisable pour les variables initiales, qui sont de meme nature (dimension) que les CPs, c'est le role du cercle des corrélations.
cordialement
Julien Delafontaine
mai 9, 2016 à 1:10
C'est la même chose. Les composantes principales sont les axes, après rotation, et ce sont des vecteur propres. De plus, après rotation, on a le même nombre de dimensions. C'est ensuite seulement qu'on fait une sélection (si on veut). Le cercle des corrélations est la projection des axes originaux sur les nouveaux axes - plutôt que de projeter les points.
Vincent
mai 9, 2016 à 11:46
Bonjour,
J'aurai une question sur les correspondances MDS / ACP, (j'ai fouillé à droite à gauche mais je n'ai pas trouvée de réponses claires). Le MDS ce fait pour moi à partir d'une matrices de distances, de ce fait une matrice carrée. Je me demande comment créer une matrices de distances entres différentes variables.
Si qqn à un lien sur ce topic, même dataset de départ mais deux analyses différentes du dataset (mds et acp) je suis preneur.
Merci pour cet article
Cordialement,
Vincent.
Amos
mai 29, 2016 à 10:54
Hello
Super article merci beaucoup !
Y'a juste un truc que j'arrive vraiment pas à comprendre c'est le paragraphe suivant :
"On voit par exemple que l'axe "PC1" est une combinaison de 0.86 x Petal.Length, 0.36 x de Sepal.Length et Petal.Width, et -0.08 x Sepal.Width - c'est-à-dire que la direction de la PC1 est à peu près alignée avec celle de Petal.Length et quasi perpendiculaire à celle de Sepal.Width.
Que veux tu dire par direction de PC1 est alignée avec celle de petal.Length ? idem pour perpendiculaire à Sepal.Width
Merci
Julien Delafontaine
juin 1, 2016 à 4:26
La PC1 est un vecteur dans un espace de dimension 4 qui est une combinaison linéaire des 4 vecteurs d'origine. De la même façon qu'en dim 2 ou 3, les composantes indiquent dans quelle direction pointe ce vecteur - là où les composantes sont grandes.
Justine
juillet 19, 2016 à 11:20
Bonjour,
Merci pour cet article.
J'aimerai savoir s'il est possible de récupérer les coordonnées des individus sur l'axe 1 et d'obtenir le cercle des corrélations des variables.
Je vous remercie.
Cordialement,
Justine
modou Niang
août 8, 2016 à 5:49
Bonjour,
J'aimerais comment vous avez fait pour remplacer les variables d'origines par les vecteurs propres.
ILLO Hamissou
octobre 5, 2016 à 11:06
Bonsoir,
Je souhaite faire une NMS ou nMDS avec R. Mais je n'y me retrouve absolument pas.
Aliou NIANG
juillet 17, 2017 à 5:14
je souhaite faire une ACP avec mes données.quelles sont les commandes que je peux utiliser et comment faire aussi la visualisation des résultats
ZaZo0o
juillet 18, 2017 à 4:19
Bonjour,
avez-vous lu l'article? Il décrit précisément la procédure...
Osias Frantzlande
août 19, 2017 à 5:38
Très instructif comme article. Comment faire pou avoir la table des cosinus relative à l'ACP pour faire des interprétations?( les commandes 🙂 ]
Allali
avril 20, 2018 à 2:23
Bonjour,
je souhaite savoir comment vous avez reconnu les types de plantes selon votre représentation de acp à un moment vous avez identifier la setosa comme une plante qu'on peut distinguer et je ne comprend pas comment vous l'avez reconnu
ZaZo0o
avril 23, 2018 à 11:05
Bonjour,
les donnnées contenues dans pca$x conservent le même ordre que dans la matrice utilisée pour faire la PCA (pca$x et iris contiennent 150 valeurs).
La 5ème colonne de iris contient le nom des espèces associées à chacune des valeurs mesurées, donc il est facile de retrouver à quel espèce correspond les valeurs dans pca$x, d'où la formule utilisée pour le graph:
plot(pca$x[,1:2], col=iris[,5]) => Graphique des 2 première PC (pca$x[,1:2]) et coloré en fonction du nom des espèces (col=iris[,5]).
Lisa
octobre 25, 2022 à 6:31
Merci pour vos explication tres clair. Comment applique le rincipe de ACP pour reduire les donnees dans le cadre de mesures repetees...?