Formation ML / Apprentissage non supervisé

PCA (analyse en composantes principales)

Intermédiaire 40 min 13 sections

Dix dimensions ramenées à deux en gardant les directions de variance maximale, et ce que le reste emporte.

Objectifs d'apprentissage

  • Comprendre le concept de réduction de dimensionnalité
  • Interpréter les composantes principales et la variance expliquée
  • Implémenter PCA avec scikit-learn
  • Visualiser des données haute dimension en 2D

Prérequis

Notions de base en algèbre linéaire (vecteurs, matrices)

Le code de cette page s'exécute dans votre navigateur. Le premier lancement télécharge Python et ses bibliothèques.

Théorie

Pourquoi réduire la dimensionnalité?

La PCA (Principal Component Analysis) est une technique de réduction de dimensionnalité qui transforme des données à N dimensions en M dimensions (M < N).

Problèmes des données haute dimension:

  • Difficulté de visualisation (>3D impossible)
  • "Fléau de la dimension" (distances deviennent similaires)
  • Overfitting (trop de features pour peu de données)
  • Temps de calcul élevé

Ce que fait la PCA:

  1. Trouve les directions de variance maximale
  2. Projette les données sur ces directions
  3. Garde les M premières directions (composantes)

Avantages:

  • Réduit la complexité tout en préservant l'information
  • Supprime les corrélations entre features
  • Facilite la visualisation
  • Peut améliorer les performances des modèles

Limitations:

  • Transformation linéaire uniquement
  • Perte d'information (même si minimisée)
  • Composantes moins interprétables
Théorie

Schéma: Comment fonctionne la PCA

Principe géométrique:

flowchart TD D["Données Originales
(10 dimensions)"] V["Trouver les directions
de variance maximale"] PC["Composantes Principales
PC1, PC2, ... PC10"] S["Sélectionner les top M
(ex: 2 composantes)"] R["Données Réduites
(2 dimensions)"] D --> V --> PC --> S --> R class R ml-node-accent

Variance expliquée:

flowchart LR subgraph Composantes ["Composantes"] PC1["PC1
65% variance"] PC2["PC2
25% variance"] PC3["PC3
7% variance"] PCN["...
3% variance"] end T["Total: 100%"] PC1 --> T PC2 --> T PC3 --> T PCN --> T KEEP["Garder PC1 + PC2
= 90% info"] class PC1 ml-node-accent class PC2 ml-node-brand class KEEP ml-node-main

La PCA trouve les axes qui "étirent" le plus les données.

Exemple concret avec code couleur - Projection PCA:

Donnée originale (3 dimensions):

  • $\textcolor{#3498db}{x_1 = 2.5}$ (taille en cm)
  • $\textcolor{#e67e22}{x_2 = 1.8}$ (largeur en cm)
  • $\textcolor{#9B7AC4}{x_3 = 3.2}$ (poids en g)

La PCA a trouvé que PC1 = $\textcolor{#27ae60}{0.6} \cdot x_1 + \textcolor{#27ae60}{0.5} \cdot x_2 + \textcolor{#27ae60}{0.6} \cdot x_3$

Étape 1 - Projection sur PC1:

$PC1 = \textcolor{#27ae60}{0.6} \times \textcolor{#3498db}{2.5} + \textcolor{#27ae60}{0.5} \times \textcolor{#e67e22}{1.8} + \textcolor{#27ae60}{0.6} \times \textcolor{#9B7AC4}{3.2}$

$PC1 = \textcolor{#3498db}{1.50} + \textcolor{#e67e22}{0.90} + \textcolor{#9B7AC4}{1.92} = \textcolor{#27ae60}{\mathbf{4.32}}$

Interprétation:

  • 3 dimensions → 1 dimension ($\textcolor{#27ae60}{PC1 = 4.32}$)
  • Cette valeur résumé 65% de l'information originale
  • La contribution de chaque feature: $\textcolor{#3498db}{1.50}$ (taille) + $\textcolor{#e67e22}{0.90}$ (largeur) + $\textcolor{#9B7AC4}{1.92}$ (poids)

Légende des couleurs:

  • $\textcolor{#3498db}{Bleu}$: Feature 1 / taille ($\textcolor{#3498db}{x_1}$)
  • $\textcolor{#e67e22}{Orange}$: Feature 2 / largeur ($\textcolor{#e67e22}{x_2}$)
  • $\textcolor{#9B7AC4}{Violet}$: Feature 3 / poids ($\textcolor{#9B7AC4}{x_3}$)
  • $\textcolor{#27ae60}{Vert}$: Poids de projection et résultat PC1
Avancé Exercice manuel: À vous de calculer!

Objectif: Comprendre PCA à la main (centrage, variance, projection).

CONTEXTE

4 points en 2D :

Pointx1x2
A24
B46
C68
D810

PARTIE 1 : Centrage des données

1.1) Calculez la moyenne de x1 et x2 1.2) Calculez les coordonnées centrées de chaque point

PARTIE 2 : Variance

2.1) Calculez la variance de x1 centre 2.2) Calculez la variance de x2 centre 2.3) Calculez la covariance entre x1 et x2

PARTIE 3 : Interprétation

3.1) Les variables sont-elles corrélées ? 3.2) Dans quelle direction la variance est-elle maximale ? 3.3) Si on réduit à 1D, combien de variance conserve-t-on approximativement ?

Avancé Solution de l'exercice manuel

SOLUTION DÉTAILLÉE

PARTIE 1 : Centrage des données

1.1) Moyennes :

$$\bar{x_1} = \frac{2+4+6+8}{4} = \textcolor{#9B7AC4}{5}$$

$$\bar{x_2} = \frac{4+6+8+10}{4} = \textcolor{#9B7AC4}{7}$$

1.2) Coordonnées centrées :

Pointx1 - 5x2 - 7
A-3-3
B-1-1
C+1+1
D+3+3

PARTIE 2 : Variance

2.1) Variance de x1 :

$$Var(x_1) = \frac{(-3)^2 + (-1)^2 + 1^2 + 3^2}{4} = \frac{9+1+1+9}{4} = \textcolor{#3498db}{5}$$

2.2) Variance de x2 :

$$Var(x_2) = \frac{9+1+1+9}{4} = \textcolor{#e67e22}{5}$$

2.3) Covariance :

$$Cov(x_1,x_2) = \frac{(-3)(-3)+(-1)(-1)+(1)(1)+(3)(3)}{4}$$

$$= \frac{9+1+1+9}{4} = \textcolor{#27ae60}{5}$$

PARTIE 3 : Interprétation

3.1) Corrélation :

$$\rho = \frac{Cov}{\sqrt{Var_1 \cdot Var_2}} = \frac{5}{\sqrt{5 \times 5}} = \textcolor{#e74c3c}{1}$$

Corrélation parfaite ! (points sur une droite)

3.2) Direction de variance max : La diagonale (45°)

$$PC_1 = (\frac{1}{\sqrt{2}}, \frac{1}{\sqrt{2}})$$

3.3) Variance conservée en 1D : La variance totale = 5 + 5 = 10 Sur PC1 ≈ $\textcolor{#27ae60}{100\%}$ (corrélation parfaite)

$\boxed{\text{1 composante suffit car les points sont alignés}}$

Légende : $\textcolor{#9B7AC4}{Violet}$: moyennes, $\textcolor{#3498db}{Bleu}$: Var(x1), $\textcolor{#e67e22}{Orange}$: Var(x2)

Code

Explorer les données haute dimension

print("=" * 70)
print("    EXPLORATION DES DONNEES HAUTE DIMENSION")
print("=" * 70)

print("\n" + "=" * 70)
print("1. APERCU DU DATASET")
print("=" * 70)
print("""
Ce dataset illustre le probleme de la haute dimensionnalite.
Avec 10 features, impossible de visualiser directement les donnees!

La PCA va nous permettre de reduire a 2D tout en preservant
l'information essentielle.
""")
display(df.head(10), title="Dataset Haute Dimension")

print(f"\n  Dimensions du dataset:")
print(f"    • {df.shape[0]} echantillons")
print(f"    • {df.shape[1]} colonnes (dont 1 categorie)")
print(f"    • {df.shape[1] - 1} features numeriques")

print("\n" + "=" * 70)
print("2. DISTRIBUTION DES CATEGORIES")
print("=" * 70)
cat_counts = df['category'].value_counts()
print("\nRepartition des categories:")
print("-" * 40)
for cat, count in cat_counts.items():
    pct = count / len(df) * 100
    bar = "█" * int(pct / 3)
    print(f"  Categorie {cat}: {count:3d} ({pct:.0f}%)  {bar}")

print(f"""
Notre objectif:
  → Reduire de 10 dimensions a 2 dimensions
  → Verifier si les categories restent separables
""")

print("\n" + "=" * 70)
print("3. MATRICE DE CORRELATIONS")
print("=" * 70)
print("""
Les correlations entre features sont importantes pour la PCA.
Des features tres correlees contiennent de l'information redondante
que la PCA va "compresser" en une seule composante.
""")

numeric_cols = [c for c in df.columns if c != 'category']
corr = df[numeric_cols].corr()
display(corr.round(2), title="Correlations entre features")

# Analyser les correlations
print("\n" + "-" * 40)
print("ANALYSE DES CORRELATIONS:")
print("-" * 40)

strong_corr = []
for i in range(len(numeric_cols)):
    for j in range(i+1, len(numeric_cols)):
        c = abs(corr.iloc[i, j])
        if c > 0.5:
            strong_corr.append((numeric_cols[i], numeric_cols[j], corr.iloc[i, j]))

if strong_corr:
    print("\n  Correlations fortes detectees (|r| > 0.5):")
    for f1, f2, c in sorted(strong_corr, key=lambda x: abs(x[2]), reverse=True)[:5]:
        print(f"    • {f1} <-> {f2}: {c:+.2f}")
    print("\n  → Ces correlations seront capturees par la PCA!")
else:
    print("\n  Pas de correlations fortes detectees.")
    print("  → Chaque feature apporte de l'information unique.")

print("\n" + "=" * 70)
print("RESUME")
print("=" * 70)
print(f"""
Nous avons {len(numeric_cols)} features - impossible a visualiser!

La PCA va:
  1. Trouver les directions de variance maximale
  2. Projeter les donnees sur ces directions
  3. Nous permettre de visualiser en 2D
""")
Ctrl+Entrée

Cliquez sur « Exécuter » pour voir le résultat.

Code

Visualiser le problème de la haute dimension

print("=" * 70)
print("    LE PROBLEME: VISUALISER 10 DIMENSIONS")
print("=" * 70)
print("""
Avec 10 features, on ne peut visualiser que des PAIRES de features.
Cela donne 10×9/2 = 45 graphiques possibles!

Prenons quelques paires pour voir le probleme.
""")

fig, axes = plt.subplots(2, 2, figsize=(12, 10))
colors = {'A': '#9B7AC4', 'B': '#C09CF0', 'C': '#F7E64D'}

# Feature 1 vs Feature 2
for cat in df['category'].unique():
    mask = df['category'] == cat
    axes[0, 0].scatter(df[mask]['feature_1'], df[mask]['feature_2'],
                   c=colors[cat], label=f'Cat {cat}', alpha=0.7, s=50)
axes[0, 0].set_xlabel('Feature 1')
axes[0, 0].set_ylabel('Feature 2')
axes[0, 0].set_title('Feature 1 vs Feature 2')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

# Feature 3 vs Feature 4
for cat in df['category'].unique():
    mask = df['category'] == cat
    axes[0, 1].scatter(df[mask]['feature_3'], df[mask]['feature_4'],
                   c=colors[cat], label=f'Cat {cat}', alpha=0.7, s=50)
axes[0, 1].set_xlabel('Feature 3')
axes[0, 1].set_ylabel('Feature 4')
axes[0, 1].set_title('Feature 3 vs Feature 4')
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)

# Feature 5 vs Feature 6
for cat in df['category'].unique():
    mask = df['category'] == cat
    axes[1, 0].scatter(df[mask]['feature_5'], df[mask]['feature_6'],
                   c=colors[cat], label=f'Cat {cat}', alpha=0.7, s=50)
axes[1, 0].set_xlabel('Feature 5')
axes[1, 0].set_ylabel('Feature 6')
axes[1, 0].set_title('Feature 5 vs Feature 6')
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)

# Feature 7 vs Feature 8
for cat in df['category'].unique():
    mask = df['category'] == cat
    axes[1, 1].scatter(df[mask]['feature_7'], df[mask]['feature_8'],
                   c=colors[cat], label=f'Cat {cat}', alpha=0.7, s=50)
axes[1, 1].set_xlabel('Feature 7')
axes[1, 1].set_ylabel('Feature 8')
axes[1, 1].set_title('Feature 7 vs Feature 8')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print("\n" + "=" * 70)
print("LE PROBLEME")
print("=" * 70)
print("""
Ce que nous observons:
  • Chaque graphique ne montre que 2 features sur 10
  • Les categories se chevauchent souvent
  • On ne voit pas la structure globale des donnees
  • Impossible de trouver la "meilleure" vue manuellement

LA SOLUTION - PCA:
  → Trouver automatiquement les 2 meilleures dimensions
  → Combiner les 10 features en 2 composantes optimales
  → Maximiser la separation visible des donnees
""")
Ctrl+Entrée

Cliquez sur « Exécuter » pour voir le résultat.

Contenu verrouillé
6 / 13

Continuez votre apprentissage

Vous avez exploré 6 sections de ce module. Connectez-vous pour débloquer le reste du cours, incluant les exercices pratiques et les solutions.

Ctrl ou Cmd plus Entrée exécute le code. Tab indente ; Échap puis Tab quitte l'éditeur.