Analyse en Composantes Principales (PCA) : Guide Complet
Résumé
L’Analyse en Composantes Principales (ACP, ou Principal Component Analysis en anglais) est l’une des méthodes de réduction de dimension les plus fondamentales et les plus utilisées en apprentissage automatique. Son objectif est simple mais puissant : transformer un ensemble de variables potentiellement corrélées en un nouvel ensemble de variables non corrélées, appelées composantes principales, tout en conservant un maximum d’information (variance) présente dans les données originales.
En pratique, cela signifie passer d’un espace à 100 dimensions vers un espace à 10 dimensions, tout en préservant 95 % de la variabilité des données. Le PCA est une méthode non supervisée — il ne requiert aucune étiquette — et repose sur des fondements mathématiques solides d’algèbre linéaire : décomposition en valeurs propres, SVD (décomposition en valeurs singulières), et maximisation de la variance projetée.
Principe Mathématique
Matrice de Covariance
Soit une matrice de données centrées X de dimensions n × p, où n est le nombre d’observations et p le nombre de variables. La première étape consiste à calculer la matrice de covariance :
S = (1 / (n − 1)) · XᵀX
Cette matrice symétrique de taille p × p encode toutes les relations linéaires entre les variables. Les éléments diagonaux représentent les variances de chaque variable, tandis que les éléments hors diagonale capturent les covariances entre paires de variables.
Décomposition en Valeurs Propres
Le cœur théorique du PCA repose sur la décomposition en valeurs propres de la matrice de covariance :
S · V = λ · V
où :
– V est la matrice dont les colonnes sont les vecteurs propres de S. Chaque vecteur propre définit une direction dans l’espace des données — c’est une composante principale.
– λ est un vecteur contenant les valeurs propres λ₁ ≥ λ₂ ≥ … ≥ λₚ ≥ 0 associées. Chaque valeur propre mesure la quantité de variance capturée par la composante principale correspondante.
Les composantes principales sont orthogonales entre elles — elles sont parfaitement non corrélées — et sont ordonnées par ordre décroissant d’importance (variance expliquée).
Décomposition SVD (Singular Value Decomposition)
En pratique, la plupart des implémentations modernes du PCA utilisent la décomposition en valeurs singulières (SVD) directement sur la matrice X, plutôt que de calculer explicitement la matrice de covariance. La SVD décompose X comme suit :
X = U · Σ · Vᵀ
où :
– U (n × p) : matrice des vecteurs singuliers à gauche (orthogonale)
– Σ (p × p) : matrice diagonale des valeurs singulières σ₁ ≥ σ₂ ≥ … ≥ σₚ ≥ 0
– V (p × p) : matrice des vecteurs propres (composantes principales), orthogonale
La relation entre valeurs propres et valeurs singulières est directe :
λⱼ = σⱼ² / (n − 1)
La SVD est numériquement plus stable que le calcul direct de S·V = λ·V, surtout lorsque les variables sont nombreuses ou fortement corrélées. C’est pourquoi elle constitue le choix par défaut dans scikit-learn.
Variance Expliquée
La variance expliquée par la k-ième composante principale est définie par :
vₖ = λₖ / Σⱼ λⱼ
C’est-à-dire le ratio de la k-ième valeur propre sur la somme totale de toutes les valeurs propres. Cette proportion indique quelle fraction de l’information totale est contenue dans chaque composante.
La variance expliquée cumulée pour les m premières composantes est :
V_cumulée = Σₖ₌₁ᵐ λₖ / Σⱼ₌₁ᵖ λⱼ
Ce critère est essentiel pour choisir le nombre optimal de composantes à retenir.
Intuition : Trouver les Meilleurs Angles de Vue
Imaginez que vous devez photographier un objet tridimensionnel, mais que vous ne disposez que d’une caméra 2D. Quel est le meilleur angle pour capturer le plus d’informations sur la forme de l’objet ? Vous choisirez naturellement la vue qui révèle le plus de « détails », la plus grande variété de formes et de contours.
Le PCA fonctionne exactement de cette manière, mais en n dimensions. Il trouve automatiquement les angles de vue qui montrent le plus de détails — les directions dans lesquelles les données présentent le plus de dispersion (variance). La première composante principale est la direction qui maximise cette variance ; la deuxième est la direction orthogonale qui capture le plus de variance restante ; et ainsi de suite.
Comme photographier un objet 3D : PCA trouve automatiquement les meilleurs angles qui capturent le maximum d’information avec le moins de photos. Au lieu de vous perdre dans des centaines de variables redondantes, il extrait les quelques axes essentiels qui résument le comportement de vos données.
Prenons un exemple concret : si vous mesurez la taille, le poids, le tour de taille, la longueur des bras et la longueur des jambes de milliers de personnes, ces variables sont fortement corrélées. Le PCA pourrait découvrir que tout cela se réduit essentiellement à deux dimensions : une composante « taille globale » et une composante « proportion corporelle ». Ces deux axes synthétiques capturent l’essentiel de l’information avec beaucoup moins de variables.
Implémentation Python
Installation et Préparation
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris, load_digits
from sklearn.preprocessing import StandardScaler
PCA de Base avec les Données Iris
# Charger les données
iris = load_iris()
X = iris.data # 150 échantillons, 4 variables
y = iris.target
# Standardisation indispensable pour le PCA
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Appliquer le PCA
pca = PCA()
X_pca = pca.fit_transform(X_scaled)
# Affichage des valeurs propres
print("Valeurs propres :", pca.explained_variance_)
print("Variance expliquée par composante :", np.round(pca.explained_variance_ratio_, 4))
print("Variance expliquée cumulée :", np.round(np.cumsum(pca.explained_variance_ratio_), 4))
Résultat typique :
Valeurs propres : [2.938, 0.920, 0.147, 0.021]
Variance expliquée : [0.730, 0.229, 0.037, 0.005]
Variance cumulée : [0.730, 0.959, 0.996, 1.000]
Les deux premières composantes capturent 95,9 % de la variance totale. On peut ainsi réduire de 4 à 2 dimensions en ne perdant que 4,1 % d’information.
Scree Plot — Visualiser les Valeurs Propres
# Scree plot
plt.figure(figsize=(8, 5))
components = np.arange(1, len(pca.explained_variance_) + 1)
plt.bar(components, pca.explained_variance_ratio_, color='steelblue', edgecolor='black')
plt.plot(components, np.cumsum(pca.explained_variance_ratio_), 'ro-', linewidth=2, markersize=8)
plt.axhline(y=0.95, color='green', linestyle='--', label='Seuil 95 %')
plt.xlabel('Composante principale')
plt.ylabel('Proportion de variance expliquée')
plt.title('Scree Plot — Analyse en Composantes Principales (Iris)')
plt.xticks(components)
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
Le scree plot montre un « coude » net : la chute brutale entre les premières composantes et les suivantes indique combien de dimensions retenir.
Visualisation 2D des Données Projetées
# Réduction à 2 dimensions
pca_2d = PCA(n_components=2)
X_2d = pca_2d.fit_transform(X_scaled)
plt.figure(figsize=(9, 6))
for label, color in zip(range(3), ['navy', 'darkorange', 'green']):
mask = y == label
plt.scatter(X_2d[mask, 0], X_2d[mask, 1],
c=color, edgecolor='black', s=60,
label=iris.target_names[label], alpha=0.8)
pct0 = pca_2d.explained_variance_ratio_[0]
pct1 = pca_2d.explained_variance_ratio_[1]
plt.xlabel(f"CP1 ({pct0:.1%} variance)")
plt.ylabel(f"CP2 ({pct1:.1%} variance)")
plt.title("Projection PCA 2D — Dataset Iris")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
On observe que les trois espèces d’iris se séparent nettement dans l’espace des deux premières composantes principales, avec Iris setosa totalement distincte.
Visualisation 3D
from mpl_toolkits.mplot3d import Axes3D
pca_3d = PCA(n_components=3)
X_3d = pca_3d.fit_transform(X_scaled)
fig = plt.figure(figsize=(10, 7))
ax = fig.add_subplot(111, projection='3d')
for label, color in zip(range(3), ['navy', 'darkorange', 'green']):
mask = y == label
ax.scatter(X_3d[mask, 0], X_3d[mask, 1], X_3d[mask, 2],
c=color, edgecolor='black', s=50,
label=iris.target_names[label], alpha=0.8)
ax.set_xlabel("CP1")
ax.set_ylabel("CP2")
ax.set_zlabel("CP3")
ax.set_title("Projection PCA 3D — Dataset Iris")
ax.legend()
plt.tight_layout()
plt.show()
Reconstruction Inverse
Un aspect puissant du PCA est la possibilité de reconstruire les données originales à partir des composantes réduites :
# Réduction à 2 dimensions
pca_2d = PCA(n_components=2)
X_2d = pca_2d.fit_transform(X_scaled)
# Reconstruction inverse (retour à l'espace à 4 dimensions)
X_reconstructed = pca_2d.inverse_transform(X_2d)
# Calcul de l'erreur de reconstruction
mse = np.mean((X_scaled - X_reconstructed) ** 2)
variance_perdue = 1 - np.sum(pca_2d.explained_variance_ratio_)
print(f"Erreur quadratique moyenne de reconstruction : {mse:.6f}")
print(f"Variance totale perdue : {variance_perdue:.4f} ({variance_perdue*100:.1f}%)")
La reconstruction n’est jamais parfaite (sauf si on conserve toutes les composantes), mais avec 95,9 % de variance retenue, les données reconstruites sont très proches des originales.
Hyperparamètres du PCA
n_components
Le paramètre le plus important. Il détermine le nombre de composantes retenues :
- int : nombre fixe de composantes (ex:
n_components=2pour une visualisation 2D) - float (entre 0 et 1) : proportion minimale de variance à conserver (ex:
n_components=0.95pour retenir 95 % de la variance). Le PCA détermine automatiquement le nombre de composantes nécessaires. - “mle” : utilise l’estimation du maximum de vraisemblance (Minka, 2000) pour choisir automatiquement le nombre optimal de dimensions.
# Auto-sélection pour conserver 95% de variance
pca_auto = PCA(n_components=0.95, svd_solver='full')
X_reduced = pca_auto.fit_transform(X_scaled)
print(f"Composantes retenues : {X_reduced.shape[1]} sur {X_scaled.shape[1]}")
svd_solver
La méthode de décomposition utilisée :
- “auto” (défaut) : choisit automatiquement selon la taille des données
- “full” : SVD classique (LAPACK), idéal pour les datasets de taille modérée
- “arpack” : utilise ARPACK pour calculer un sous-ensemble de composantes, utile pour les grands datasets
- “randomized” : approximation stochastique rapide pour les très grands datasets (milliers de features)
# Pour les très grandes matrices
pca_fast = PCA(n_components=50, svd_solver='randomized', random_state=42)
whiten
L’option whiten=True normalise chaque composante principale pour avoir une variance unitaire :
pca_whiten = PCA(whiten=True)
Cette transformation « blanchit » les données — toutes les composantes ont alors la même échelle de variance. Utile en pré-traitement pour certains algorithmes comme les réseaux de neurones ou les SVM, qui bénéficient de données à échelle uniforme.
tol
Tolérance pour le solveur « arpack ». Définit le critère de convergence :
pca_precis = PCA(n_components=10, svd_solver='arpack', tol=1e-6)
Une tolérance plus stricte donne des résultats plus précis mais peut ralentir la convergence.
Avantages et Limites
Avantages
- Réduction efficace du bruit : les composantes de faible variance capturent souvent du bruit plutôt que du signal. Les supprimer améliore la qualité des données.
- Élimination de la multicolinéarité : les composantes principales sont par construction orthogonales et non corrélées, ce qui résout les problèmes de corrélation entre variables.
- Visualisation : réduire à 2 ou 3 dimensions permet de visualiser des données intrinsèquement multidimensionnelles.
- Prétraitement universel : le PCA accélère et améliore presque tous les algorithmes d’apprentissage subséquents en réduisant la dimension d’entrée.
- Déterministe : contrairement au t-SNE ou UMAP, le PCA est parfaitement reproductible — même données, mêmes résultats.
- Interprétabilité relative : on peut analyser les poids (loadings) de chaque variable dans chaque composante pour comprendre ce qu’elle capture.
Limites
- Linéarité : le PCA ne capture que les relations linéaires entre variables. Pour des structures non linéaires complexes, des méthodes comme t-SNE, UMAP ou les autoencodeurs sont plus appropriées.
- Sensibilité aux outliers : la variance étant basée sur les moyennes quadratiques, les valeurs extrêmes peuvent biaiser les composantes principales.
- Perte d’interprétabilité directe : chaque composante principale est une combinaison linéaire de toutes les variables originales, ce qui rend son interprétation parfois difficile.
- Standardisation nécessaire : le PCA est sensible aux échelles des variables. Sans normalisation, les variables à grande échelle dominent artificiellement.
- Aucune garantie sur la séparabilité des classes : PCA maximise la variance, pas la discrimination entre classes. Pour la classification, LDA (Analyse Discriminante Linéaire) est parfois plus pertinent.
4 Cas d’Usage Concrets
1. Compression et Traitement d’Images
Le PCA est massivement utilisé pour la compression d’images. En décomposant un ensemble de visages en composantes principales (les célèbres Eigenfaces de Turk & Pentland, 1991), on peut représenter n’importe quel visage par seulement 50 à 100 coefficients au lieu de centaines de milliers de pixels.
from sklearn.datasets import fetch_olivetti_faces
faces = fetch_olivetti_faces()
X_faces = faces.data / 255.0 # 400 images de 64×64 pixels
pca_faces = PCA(n_components=0.95)
X_faces_reduced = pca_faces.fit_transform(X_faces)
print(f"Réduction : {X_faces.shape[1]} → {X_faces_reduced.shape[1]} dimensions")
# Visualisation des Eigenfaces
fig, axes = plt.subplots(2, 5, figsize=(10, 4))
for i, ax in enumerate(axes.flat):
ax.imshow(pca_faces.components_[i].reshape(64, 64), cmap='gray')
ax.axis('off')
ax.set_title(f"CP{i+1}")
plt.suptitle("10 premières composantes principales (Eigenfaces)")
plt.tight_layout()
plt.show()
Cette approche réduit la taille des données d’un facteur 100 tout en préservant les traits faciaux essentiels.
2. Analyse Génomique et Bio-informatique
Dans les études génomiques, on mesure souvent l’expression de dizaines de milliers de gènes sur quelques centaines d’échantillons. Le PCA permet d’identifier les patterns d’expression dominants, de détecter des groupes de patients similaires, et de visualiser des données autrement inaccessibles.
Un exemple classique : réduire 20 000 gènes à 3 composantes pour révéler que les échantillons se séparent naturellement selon le type de cancer — sans aucune information de label.
3. Finance — Analyse de Portefeuille
En finance quantitative, le PCA identifie les facteurs de risque latents qui expliquent les mouvements de marchés :
- Première composante : effet de marché global (tous les actifs bougent dans la même direction)
- Deuxième composante : effet sectoriel ou taille (grandes vs petites capitalisations)
- Troisième composante : dynamiques spécifiques supplémentaires
# PCA sur les rendements d'actions
import pandas as pd
from sklearn.decomposition import PCA
np.random.seed(42)
# Simulation : 500 jours, 30 actions
rentabilites = np.random.multivariate_normal(
mean=np.zeros(30),
cov=np.eye(30) * 0.5 + 0.3, # corrélation modérée
size=500
)
pca_finance = PCA()
X_pca_fin = pca_finance.fit_transform(rentabilites)
print("Variance expliquée par facteur :")
for i in range(5):
prop = pca_finance.explained_variance_ratio_[i]
print(f" Facteur {i+1}: {prop:.2%}")
cum3 = np.sum(pca_finance.explained_variance_ratio_[:3])
print(f" Cumul 3 facteurs: {cum3:.2%}")
Souvent, les 3 premiers facteurs expliquent plus de 80 % de la variabilité totale des rendements.
4. Traitement du Langage Naturel (NLP)
Bien que Word2Vec et les transformers dominent aujourd’hui le NLP, le PCA reste utile pour :
- Réduire la dimension des embeddings (de 768 à 128 dimensions) avant de les utiliser dans un modèle plus léger
- Dé-bruiter les vecteurs de mots en supprimant les composantes de faible variance
- Visualiser l’espace sémantique : projeter des embeddings de mots en 2D pour observer les regroupements thématiques
# Réduction d'embeddings pour un modèle léger
from sklearn.decomposition import PCA
# Embeddings de 768 dimensions
embeddings = np.random.randn(10000, 768) # 10 000 mots, 768 dimensions
pca_embed = PCA(n_components=128)
embeddings_reduits = pca_embed.fit_transform(embeddings)
variance_conservee = np.sum(pca_embed.explained_variance_ratio_)
print(f"Dimensions : 768 → 128 ({variance_conservee:.1%} variance conservée)")
print(f"Réduction mémoire : {embeddings.nbytes / 1024:.0f} Ko → {embeddings_reduits.nbytes / 1024:.0f} Ko")
Cela réduit la taille du modèle par 6 tout en conservant la grande majorité de l’information sémantique.
Voir Aussi
- Maîtriser les Arrangements Maximaux en Python : Guide Complet et Astuces pour Développeurs
- Trouver la Médiane d’un Flux de Données en Python – Question d’Entretien

