Învățare nesupervizată

3.2 PCA — Analiza componentelor principale

Când ai 100 de coloane, PCA găsește câteva „direcții esențiale" care păstrează aproape toată informația — pentru vizualizare, viteză și reducerea zgomotului.

Teorie

Reducerea dimensionalității

Multe coloane spun povești suprapuse (înălțimea în cm și în inch, notele la materii înrudite). PCA construiește componente principale: combinații liniare noi ale coloanelor, alese astfel încât prima componentă să capteze cea mai mare parte din variația datelor, a doua — maximul rămas (perpendiculară pe prima), și așa mai departe.

Intuiție: datele sunt un nor de puncte; PCA rotește axele astfel încât prima axă să treacă prin „lungimea" norului. Dacă norul e plat, a treia dimensiune abia mai contează — o poți tăia.

Varianța explicată — câte componente păstrezi

explained_variance_ratio_ spune ce procent din informație duce fiecare componentă. Regulă practică: păstrezi componentele care cumulează 90–95%. Alternativ, îi ceri direct lui sklearn: PCA(n_components=0.95).

Proiecția în spații reduse

transform proiectează datele pe noile axe; inverse_transform le aduce aproximativ înapoi — diferența este informația pierdută. Proiecția pe primele 2 componente este cel mai comun mod de a desena date cu multe dimensiuni.

Implementarea scikit-learn

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import numpy as np

X = StandardScaler().fit_transform(df)   # PCA cere date standardizate

pca = PCA()
pca.fit(X)
print(pca.explained_variance_ratio_.round(3))          # per componentă
print(np.cumsum(pca.explained_variance_ratio_).round(3))  # cumulat

# păstrăm 95% din informație
pca = PCA(n_components=0.95)
X_redus = pca.fit_transform(X)
print(X.shape, "→", X_redus.shape)
Într-un pipeline de model, fit pentru PCA se face doar pe train — aceeași regulă anti-leakage ca la scalare.

Problemă rezolvată: cifre scrise de mână în 2D

Vizualizarea datasetului digits (64 dimensiuni → 2) Mediu Rezolvată

Imaginile 8×8 cu cifre au 64 de dimensiuni. Le proiectăm cu PCA în 2D ca să vedem cum se grupează cifrele, apoi măsurăm câte componente ne trebuie pentru 95% din informație.

Soluția pas cu pas
import numpy as np, matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

X, y = load_digits(return_X_y=True)      # (1797, 64)
X_s = StandardScaler().fit_transform(X)

# proiecția 2D
p2 = PCA(n_components=2).fit(X_s)
X2 = p2.transform(X_s)
plt.figure(figsize=(8, 6))
sc = plt.scatter(X2[:, 0], X2[:, 1], c=y, cmap="tab10", s=10)
plt.colorbar(sc); plt.title("Digits în primele 2 componente"); plt.show()
print("Varianță explicată de 2 componente:",
      p2.explained_variance_ratio_.sum().round(3))   # ~0.22

# câte componente pentru 95%?
p95 = PCA(n_components=0.95).fit(X_s)
print("Componente pentru 95%:", p95.n_components_)   # ~40 din 64

Interpretare: chiar cu doar ~22% din varianță, cifrele 0, 4 și 6 formează insule vizibile; cifrele asemănătoare grafic (3/8/9) se amestecă. Pentru separare vizuală mai bună → t-SNE/UMAP, lecția următoare.

Probleme propuse

1. Coloana redundantă Exercițiu

Creează un tabel cu x1 aleator, x2 = 2·x1 + zgomot mic și x3 independent. Rulează PCA și explică de ce prima componentă explică ~66% din varianță.

2. Graficul varianței cumulate Exercițiu

Pentru orice dataset tabelar de pe platformă, desenează varianța explicată cumulată în funcție de numărul de componente și marchează pragurile 90% și 95%.

3. PCA + model Exercițiu

Compară un clasificator antrenat pe datele digits complete vs pe primele 20 de componente PCA: acuratețe și timp de antrenare. Merită reducerea?

4. Compresie de imagine cu PCA Exercițiu

Aplică PCA pe liniile unei imagini în tonuri de gri și reconstruiește-o cu 5, 20 și 50 de componente. Afișează cele trei versiuni una lângă alta.