Hoppa till innehållet
AI-grafen
E· Universitetmatematik· ca 60 min· utvecklande· verifierad 2026-09-20

PCA — principalkomponentanalys

Kunna reducera dimensioner med PCA och tolka förklarad varians.

Förkunskaper

Intuition

PCA hittar de riktningar där datan varierar mest, och projicerar ner på dem.

Tänk dig ett moln av punkter som ligger utsträckt längs en diagonal. Den första principalkomponenten är den linjen. Den andra är vinkelrät mot den, längs den näst största spridningen. Och så vidare.

Varför variation? Därför att en riktning där allt ligger på samma ställe inte skiljer datapunkterna åt — den bär ingen information om vad som är olika.

Tre saker PCA används till:

AnvändningHur
Komprimering100 kolumner → 10, med 95 % av variationen kvar
Visualiseringprojicera ner till 2D och rita
Avbrusningkasta de sista komponenterna, som ofta är mätbrus

Den avgörande förberedelsen: centrera alltid datan (dra bort medelvärdet), och skala om kolumnerna har olika enheter. Annars mäter PCA enheter i stället för struktur.

Formellt

Två ekvivalenta beskrivningar:

  1. Egenvektorerna till kovariansmatrisen C=1n−1X⊤XC = \frac{1}{n-1}X^\top X (efter centrering), sorterade efter egenvärde.
  2. Högersingulärvektorerna VV från SVD av den centrerade XX.

Den andra är vad man faktiskt beräknar — den är numeriskt stabilare och behöver aldrig bilda kovariansmatrisen. Sambandet är λi=σi2/(n−1)\lambda_i = \sigma_i^2/(n-1).

Förklarad varians för komponent ii:

λi∑jλj=σi2∑jσj2\frac{\lambda_i}{\sum_j \lambda_j} = \frac{\sigma_i^2}{\sum_j \sigma_j^2}

Hur många komponenter? Tre vanliga regler:

RegelHur
Tröskelbehåll tills kumulativ varians når 90–95 %
Armbågenleta efter knäet i scree-plotten
Nedströmsvälj den som ger bäst resultat i den modell som följer

Den sista är den ärligaste när PCA är ett förbehandlingssteg.

Skalning är inte valfritt. Har du vikt i gram (0–100 000) och längd i meter (0–2) kommer den första principalkomponenten att vara vikt, oavsett vad datan egentligen handlar om. Variansen är inte enhetslös. Standardisera först, om inte alla kolumner redan har samma enhet.

Läckage: fit på träningsdatan, transform på både träning och test. Att köra fit_transform på allt är samma fel som med skalning.

Begränsningar:

BegränsningBetyder
Linjärfångar inte krökta grenrör — en spiral rullas inte ut
Varians ≠ användbarhetden viktigaste riktningen för klassificering kan ha låg varians
Svårtolkade komponentervarje komponent är en blandning av alla originalvariabler
Känslig för avvikareen extrem punkt kan dominera första komponenten

Den andra punkten är viktig: PCA är oövervakad och vet inget om etiketterna. Behöver du den riktning som bäst separerar klasser är LDA rätt verktyg, inte PCA.

För visualisering är t-SNE och UMAP ofta bättre på att visa klusterstruktur — men de bevarar inte avstånd globalt och deras utdata ska inte matas vidare in i en modell.

Kod

import numpy as np

# 800 punkter i 30 dimensioner — men egentligen bara 4 latenta faktorer plus brus
rng = np.random.default_rng(0)
Z = rng.normal(size=(800, 4))
X = Z @ rng.normal(size=(4, 30)) + 0.5 * rng.normal(size=(800, 30))

Xc = X - X.mean(axis=0)                      # CENTRERA — annars mäter PCA fel sak
U, s, Vt = np.linalg.svd(Xc, full_matrices=False)
andel = s**2 / (s**2).sum()

print(np.round(s[:8], 1))
# [196.9 152.2 134.3 120.5  16.6  16.1  15.9  15.7]
#   ↑ fyra stora, sedan ett tydligt hopp ner till brusnivån

print(np.round(andel[:6], 4))                # [0.3892 0.2324 0.1811 0.1458 0.0028 0.0026]
print(np.round(np.cumsum(andel)[:6], 4))     # [0.3892 0.6215 0.8026 0.9484 0.9511 0.9537]
print("komponenter för 95 %:", int(np.searchsorted(np.cumsum(andel), 0.95) + 1))   # 5

# Rekonstruktionsfel: hur mycket går förlorat vid k komponenter?
for k in (2, 4, 10):
    Xk = U[:, :k] * s[:k] @ Vt[:k]
    print(f"  k={k:>2}  relativt fel {np.linalg.norm(Xc - Xk) / np.linalg.norm(Xc):.4f}")
#   k= 2  relativt fel 0.6152
#   k= 4  relativt fel 0.2273      ← de fyra verkliga faktorerna
#   k=10  relativt fel 0.1913      ← knappt bättre; resten är brus

# Skalningens betydelse: en kolumn i en annan enhet
Xo = X.copy(); Xo[:, 0] *= 10_000

def andelar(M, n=2):
    s2 = np.linalg.svd(M - M.mean(axis=0), compute_uv=False) ** 2
    return np.round((s2 / s2.sum())[:n], 3)

print("utan skalning:", andelar(Xo))                                   # [1. 0.]
print("med skalning: ", andelar((Xo - Xo.mean(0)) / Xo.std(0)))        # [0.332 0.247]
#  ↑ utan standardisering äter den stora kolumnen upp hela första komponenten

I praktiken lägger man PCA i en Pipeline tillsammans med skalningen och modellen, så att fit körs om inom varje korsvalideringsveck:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score

pipe = Pipeline([("skala", StandardScaler()),
                 ("pca", PCA(n_components=20)),
                 ("klassificerare", LogisticRegression(max_iter=2000))])
print(cross_val_score(pipe, X, y, cv=5).mean())

Variera n_components och låt resultatet avgöra — det är den ärligaste regeln när PCA är ett förbehandlingssteg. Ofta slår ett urval av komponenter alla, eftersom de sista bär mest brus.

Behärskning innebär

  • Utför PCA och tolkar förklarad varians
  • Vet varför centrering och skalning behövs
  • Känner till PCA:s begränsningar

Logga in för att göra övningarna och bygga upp din behärskning.

Källor

Alla källor och licenser