Calculez une analyse en composantes principales
Un relevé de températures moyennes donne, pour chaque ville, une valeur par saison ou par mois : douze colonnes, et autant de graphiques possibles. Comment voir d’un coup d’œil quelles villes se ressemblent et ce qui les distingue ? L’analyse en composantes principales (ACP, en anglais principal component analysis ou PCA) répond à cette question : elle remplace de nombreuses variables corrélées par quelques variables nouvelles, non corrélées, qui gardent l’essentiel des différences entre individus.
Ce chapitre vous montre comment l’ACP se calcule, sur des exemples assez petits pour être suivis à la main. Le chapitre suivant apprendra à lire le résultat. Notre fil rouge : six villes françaises décrites par leur température moyenne à chaque saison.
L’idée : résumer sans perdre les différences
Section intitulée « L’idée : résumer sans perdre les différences »Commençons par un exemple minuscule. Quatre étudiants ont eu les notes suivantes :
| Français | Philosophie | Maths | Physique | |
|---|---|---|---|---|
| Étudiant 1 | 16 | 14 | 8 | 10 |
| Étudiant 2 | 17 | 15 | 7 | 9 |
| Étudiant 3 | 6 | 8 | 18 | 16 |
| Étudiant 4 | 7 | 9 | 17 | 15 |
On aimerait résumer ces quatre notes par deux nombres. Premier essai : la moyenne de français et de maths, et la moyenne de philosophie et de physique. Calculez-les : tous les étudiants obtiennent 12 et 12. Ce résumé est inutile, il efface toutes les différences.
Deuxième essai : la moyenne des matières littéraires (français, philosophie) et celle des matières scientifiques (maths, physique). On obtient 15 et 9 pour l’étudiant 1, 16 et 8 pour le 2, 7 et 17 pour le 3, 8 et 16 pour le 4. Cette fois, deux profils sautent aux yeux : deux « littéraires » et deux « scientifiques ».
Le bon résumé est donc celui qui conserve le mieux la variabilité entre les individus. L’ACP trouve automatiquement ces bonnes combinaisons, avec deux objectifs :
- transformer un grand nombre de variables corrélées en un petit nombre de variables non corrélées, les composantes principales ;
- choisir celles qui montrent le mieux la variabilité du nuage de points.
Pensez à une photographie d’un objet en trois dimensions. Selon l’angle, on reconnaît l’objet ou pas : une tasse vue de dessus n’est qu’un cercle, vue de profil on voit l’anse. L’ACP cherche l’angle de vue qui déforme le moins le nuage de points.
Deux nuages et une préparation
Section intitulée « Deux nuages et une préparation »Les données de l’ACP forment un tableau de individus (les lignes) décrits par variables quantitatives (les colonnes). Ce tableau se lit de deux façons :
- le nuage des individus : chaque individu est un point de ; on cherche quels individus se ressemblent ;
- le nuage des variables : chaque variable est un point de ; on cherche quelles variables sont liées.
Avant tout calcul, on centre toujours les données : on retire à chaque variable sa moyenne, , où est la valeur de la variable pour l’individu et la moyenne de la variable . L’origine se place alors au centre de gravité du nuage, sans en changer la forme.
On réduit aussi, le plus souvent : , où est l’écart-type de la variable . C’est indispensable dès que les variables n’ont pas la même unité ou le même ordre de grandeur : sans réduction, une variable exprimée en euros (variance énorme) écraserait une variable exprimée en années. On parle alors d’ACP normée. Dans la suite, on note le tableau centré-réduit.
Le critère : l’inertie projetée
Section intitulée « Le critère : l’inertie projetée »Pour mesurer la dispersion d’un nuage à plusieurs dimensions, on généralise la variance : c’est l’inertie, la moyenne des carrés des distances des points au centre de gravité .
où est le point représentant l’individu . L’inertie totale est donc la somme des variances des variables. En ACP normée, chaque variable a une variance de 1, et l’inertie totale vaut simplement .
Projetons maintenant chaque point sur un axe passant par l’origine (le centre de gravité, puisque les données sont centrées). Appelons son projeté.
Le triangle est rectangle en , donc par Pythagore : . La longueur ne dépend pas de l’axe choisi. Par conséquent, minimiser la déformation revient exactement à maximiser l’inertie projetée : l’axe qui déforme le moins le nuage est celui sur lequel les projections sont les plus étalées.
L’ACP procède alors pas à pas :
- trouver l’axe d’inertie projetée maximale ;
- trouver l’axe , orthogonal à , d’inertie projetée maximale ; le plan est le meilleur plan ;
- continuer avec orthogonal aux deux premiers, et ainsi de suite jusqu’à axes.
Le calcul : valeurs et vecteurs propres
Section intitulée « Le calcul : valeurs et vecteurs propres »Rappelons qu’un vecteur non nul est un vecteur propre d’une matrice carrée si : la matrice ne fait que l’allonger ou le raccourcir, d’un facteur appelé valeur propre. On montre que les axes cherchés sont les vecteurs propres de la matrice des corrélations. Le calcul tient en quatre étapes.
- Calculer la matrice des corrélations , où est le tableau centré-réduit. C’est une matrice symétrique, dont le terme est la corrélation entre les variables et .
- Calculer ses valeurs propres et ses vecteurs propres unitaires . Comme est symétrique, ces vecteurs sont orthogonaux deux à deux.
- L’axe est dirigé par . La composante principale donne la coordonnée de chaque individu sur cet axe. Elle est de moyenne nulle et de variance .
- L’inertie expliquée par l’axe vaut ; celle du plan vaut . La somme de toutes les valeurs propres est l’inertie totale, en ACP normée.
Plus généralement, pour deux variables de corrélation positive, les valeurs propres valent et : plus la corrélation est forte, plus le premier axe résume à lui seul.
Et nos quatre étudiants ? Leurs notes sont presque parfaitement corrélées (plus de 0,99 en valeur absolue). L’ACP normée donne , soit 99,9 % de l’inertie sur le premier axe, dirigé par . La première composante vaut donc la moitié de (français + philosophie − maths − physique), en notes standardisées : c’est exactement l’opposition « littéraire contre scientifique » que nous avions devinée.
Le fil rouge : six villes, quatre saisons
Section intitulée « Le fil rouge : six villes, quatre saisons »Voici maintenant un exemple plus réaliste. Les températures moyennes (en °C, valeurs arrondies construites pour l’exemple) de six villes sont :
| Ville | Hiver | Printemps | Été | Automne |
|---|---|---|---|---|
| Brest | 7,0 | 10,5 | 16,5 | 12,0 |
| Rennes | 5,5 | 11,0 | 18,0 | 12,0 |
| Strasbourg | 1,5 | 10,5 | 19,5 | 10,0 |
| Lyon | 3,5 | 12,0 | 21,5 | 12,5 |
| Nice | 9,5 | 13,5 | 23,0 | 17,0 |
| Marseille | 8,0 | 14,0 | 24,0 | 16,0 |
Toutes les variables sont en degrés, mais leurs variances diffèrent ; on fait une ACP normée. La matrice des corrélations vaut (arrondie au millième) :
| Hiver | Printemps | Été | Automne | |
|---|---|---|---|---|
| Hiver | 1 | 0,658 | 0,345 | 0,870 |
| Printemps | 0,658 | 1 | 0,926 | 0,933 |
| Été | 0,345 | 0,926 | 1 | 0,757 |
| Automne | 0,870 | 0,933 | 0,757 | 1 |
Toutes les corrélations sont positives : une ville chaude à une saison a tendance à l’être aux autres. Mais l’hiver et l’été ne sont liés qu’à 0,345, signe qu’il existe une seconde source de différences. Les valeurs propres de cette matrice sont :
| Axe | Valeur propre | % d’inertie | % cumulé |
|---|---|---|---|
| 1 | 3,273 | 81,8 % | 81,8 % |
| 2 | 0,714 | 17,9 % | 99,7 % |
| 3 | 0,011 | 0,3 % | 99,9 % |
| 4 | 0,002 | 0,1 % | 100 % |
Les vecteurs propres des deux premiers axes sont et , dans l’ordre hiver, printemps, été, automne. Le premier axe donne un poids positif et comparable aux quatre saisons : il mesure si une ville est chaude toute l’année. Le second oppose l’hiver (poids positif) à l’été (poids négatif) : il mesure la douceur de l’hiver par rapport à l’été, autrement dit l’amplitude thermique. Le chapitre suivant confirmera cette lecture.
Combien d’axes garder ?
Section intitulée « Combien d’axes garder ? »Trois critères coexistent :
- le pourcentage d’inertie cumulé : ; les axes étant orthogonaux, les pourcentages s’additionnent. On garde assez d’axes pour atteindre un seuil fixé selon l’usage (souvent 80 à 90 %) ;
- le coude dans le diagramme des valeurs propres (l’éboulis) : on s’arrête là où la décroissance devient brutalement plus lente ;
- le critère de Kaiser, en ACP normée : on garde les axes de valeur propre supérieure à 1, c’est-à-dire ceux qui résument plus d’information qu’une variable d’origine à elle seule.
Pour nos villes, le plan explique 99,7 % de l’inertie : il est inutile d’aller plus loin. L’exemple classique de 15 grandes villes françaises décrites par leurs 12 températures mensuelles donne un résultat très proche : près de 80 % de l’inertie sur le premier axe, près de 19 % sur le second, soit presque 99 % pour le plan.
En pratique : la SVD et scikit-learn
Section intitulée « En pratique : la SVD et scikit-learn »Les logiciels ne diagonalisent pas directement : ils passent par la décomposition en valeurs singulières (SVD) du tableau centré-réduit, , où et ont des colonnes orthonormées et est diagonale, de termes (les valeurs singulières). On en déduit : les axes principaux sont les colonnes de , et les valeurs propres valent . Ce calcul est plus stable numériquement, et il évite de former la matrice .
import pandas as pdfrom sklearn.decomposition import PCAfrom sklearn.preprocessing import StandardScaler
villes = pd.DataFrame( {"hiver": [7.0, 5.5, 1.5, 3.5, 9.5, 8.0], "printemps": [10.5, 11.0, 10.5, 12.0, 13.5, 14.0], "ete": [16.5, 18.0, 19.5, 21.5, 23.0, 24.0], "automne": [12.0, 12.0, 10.0, 12.5, 17.0, 16.0]}, index=["Brest", "Rennes", "Strasbourg", "Lyon", "Nice", "Marseille"])
Z = StandardScaler().fit_transform(villes) # centrer-réduire (écart-type divisé par n)acp = PCA().fit(Z)print(acp.explained_variance_ratio_.round(3)) # [0.818 0.179 0.003 0.001]print(acp.components_[:2].round(3)) # u1 et u2 (au signe près)F = acp.transform(Z) # coordonnées des villes sur les axesEn résumé
Section intitulée « En résumé »- L’ACP remplace variables quantitatives corrélées par des composantes principales non corrélées qui conservent au mieux la variabilité du nuage.
- On centre toujours les données, et on les réduit dès que les unités ou les ordres de grandeur diffèrent (ACP normée).
- Le critère est l’inertie projetée : par Pythagore, la maximiser revient à déformer le nuage le moins possible.
- Les axes sont les vecteurs propres de la matrice des corrélations ; chaque valeur propre est l’inertie (la variance) expliquée par l’axe ; leur somme vaut en ACP normée.
- Sur les six villes, le premier axe (81,8 %) mesure la chaleur générale, le second (17,9 %) l’amplitude thermique.
- On choisit le nombre d’axes par le pourcentage cumulé, le coude ou le critère de Kaiser (), qui peut être trop sévère.
Exercices
Section intitulée « Exercices »Exercice · Reconnaître un vecteur propre
facileSoit . Les vecteurs et sont-ils des vecteurs propres de ? Si oui, avec quelle valeur propre ? Le vecteur est aussi un vecteur propre de : est-il orthogonal à ? Qu’en concluez-vous ?
Voir la solution
- : est vecteur propre, de valeur propre 4.
- , qui n’est pas proportionnel à : n’est pas vecteur propre.
- : vecteur propre de valeur propre . Son produit scalaire avec vaut : ils ne sont pas orthogonaux.
Conclusion : les vecteurs propres d’une matrice quelconque ne sont pas forcément orthogonaux. Ils le sont pour une matrice symétrique, comme la matrice des corrélations de l’ACP : c’est ce qui garantit des axes perpendiculaires.
En code
import numpy as np
A = np.array([[2, 3], [2, 1]])v, w, t = np.array([3, 2]), np.array([2, 3]), np.array([1, -1])
print(A @ v, A @ w, A @ t) # [12 8] = 4 v ; [13 7] non proportionnel ; [-1 1] = -1 tprint(v @ t) # 1 : v et t ne sont pas orthogonauxprint(np.linalg.eigvals(A).real) # [ 4. -1.]
# Une matrice symétrique, elle, a des vecteurs propres orthogonauxS = np.array([[1, 0.8], [0.8, 1]])_, vecteurs = np.linalg.eigh(S)print(round(vecteurs[:, 0] @ vecteurs[:, 1], 10)) # 0.0A <- matrix(c(2, 3, 2, 1), nrow = 2, byrow = TRUE)v <- c(3, 2); w <- c(2, 3); t1 <- c(1, -1)
A %*% v; A %*% w; A %*% t1 # (12, 8) = 4 v ; (13, 7) non proportionnel ; (-1, 1) = -1 t1sum(v * t1) # 1 : v et t1 ne sont pas orthogonauxeigen(A)$values # 4 -1
# Une matrice symétrique, elle, a des vecteurs propres orthogonauxS <- matrix(c(1, 0.8, 0.8, 1), 2)vecteurs <- eigen(S)$vectorsround(sum(vecteurs[, 1] * vecteurs[, 2]), 10) # 0Exercice · Une ACP à deux variables
moyenDeux variables standardisées ont une corrélation .
- Écrivez la matrice des corrélations et vérifiez que et sont des vecteurs propres. Quelles sont les valeurs propres ?
- Quel pourcentage d’inertie le premier axe explique-t-il ?
- Un individu a pour valeurs standardisées . Calculez ses coordonnées et .
Voir la solution
- . Pour : . Pour : . Les valeurs propres sont (axe ) et (axe ). Leur somme vaut bien 2.
- . Avec une corrélation négative, le premier axe oppose les deux variables au lieu de les additionner.
- et . L’individu est entièrement porté par le premier axe : il est fort sur la première variable et faible sur la seconde, exactement l’opposition que résume .
En code
import numpy as np
R = np.array([[1, -0.6], [-0.6, 1]])a = np.array([1, -1]) / np.sqrt(2)b = np.array([1, 1]) / np.sqrt(2)print(R @ a / a, R @ b / b) # [1.6 1.6] [0.4 0.4] : valeurs propres 1.6 et 0.4
lambdas = np.array([1.6, 0.4])print(lambdas[0] / lambdas.sum()) # 0.8 : 80 % de l'inertie sur l'axe 1
z = np.array([1, -1])print(round(z @ a, 3), z @ b) # F1 = 1.414, F2 = 0.0R <- matrix(c(1, -0.6, -0.6, 1), 2)a <- c(1, -1) / sqrt(2)b <- c(1, 1) / sqrt(2)drop(R %*% a) / a; drop(R %*% b) / b # 1.6 1.6 ; 0.4 0.4 : valeurs propres
lambdas <- eigen(R)$values # 1.6 0.4lambdas[1] / sum(lambdas) # 0.8 : 80 % de l'inertie sur l'axe 1
z <- c(1, -1)round(c(F1 = sum(z * a), F2 = sum(z * b)), 3) # F1 = 1.414, F2 = 0Exercice · Pourquoi la variance d'une composante vaut λ
difficileSoit un tableau centré-réduit ( lignes, colonnes), , et un vecteur propre unitaire de de valeur propre . On pose .
- Montrez que est de moyenne nulle.
- Montrez que sa variance vaut .
- Déduisez-en que la somme des valeurs propres vaut .
Voir la solution
- La moyenne de est . Chaque colonne de est centrée, donc chaque parenthèse est nulle : la moyenne vaut 0.
- Comme la moyenne est nulle, la variance est la moyenne des carrés : . Or , donc , puisque est unitaire.
- La somme des valeurs propres d’une matrice est égale à sa trace (la somme de ses termes diagonaux). La diagonale de contient les corrélations de chaque variable avec elle-même, toutes égales à 1 : la trace vaut . C’est bien l’inertie totale d’une ACP normée, répartie entre les axes.
En code
import numpy as np
# Vérification sur les six villes du chapitreX = np.array([[7.0, 10.5, 16.5, 12.0], [5.5, 11.0, 18.0, 12.0], [1.5, 10.5, 19.5, 10.0], [3.5, 12.0, 21.5, 12.5], [9.5, 13.5, 23.0, 17.0], [8.0, 14.0, 24.0, 16.0]])I, K = X.shapeZ = (X - X.mean(axis=0)) / X.std(axis=0) # centré-réduit (écart-type divisé par I)R = Z.T @ Z / Ilambdas, U = np.linalg.eigh(R) # vecteurs propres unitaires en colonnesF = Z @ U # toutes les composantes d'un coup
print(F.mean(axis=0).round(10)) # [0. -0. -0. -0.] : moyennes nullesprint(F.var(axis=0).round(3)) # [0.002 0.011 0.714 3.273]print(lambdas.round(3)) # les mêmes : Var(F_s) = lambda_sprint(round(lambdas.sum(), 6), round(np.trace(R), 6)) # 4.0 4.0 : somme = trace = K# Vérification sur les six villes du chapitreX <- matrix(c(7.0, 10.5, 16.5, 12.0, 5.5, 11.0, 18.0, 12.0, 1.5, 10.5, 19.5, 10.0, 3.5, 12.0, 21.5, 12.5, 9.5, 13.5, 23.0, 17.0, 8.0, 14.0, 24.0, 16.0), ncol = 4, byrow = TRUE)I <- nrow(X); K <- ncol(X)ecart_n <- function(x) sqrt(mean((x - mean(x))^2)) # écart-type divisé par IZ <- scale(X, center = TRUE, scale = apply(X, 2, ecart_n))R <- t(Z) %*% Z / Ie <- eigen(R) # vecteurs propres unitaires en colonnesF <- Z %*% e$vectors # toutes les composantes d'un coup
round(colMeans(F), 10) # 0 0 0 0 : moyennes nullesround(colMeans(F^2), 3) # variances : 3.273 0.714 0.011 0.002round(e$values, 3) # les mêmes : Var(F_s) = lambda_sc(sum(e$values), sum(diag(R))) # 4 4 : somme = trace = K