@amoeba ha avuto risposte eccellenti alle domande sulla PCA, inclusa questa sulla relazione tra SVD e PCA. Rispondendo alla tua domanda esatta farò tre punti:
- matematicamente non c'è differenza se si calcola il PCA direttamente sulla matrice di dati o sulla sua matrice di covarianza
- la differenza è dovuta esclusivamente alla precisione e alla complessità numerica. L'applicazione di SVD direttamente alla matrice di dati è numericamente più stabile rispetto alla matrice di covarianza
- L'SVD può essere applicato alla matrice di covarianza per eseguire la PCA o ottenere valori di autigeni, infatti è il mio metodo preferito per risolvere i problemi di autigeni
Si scopre che SVD è più stabile rispetto alle tipiche procedure di decomposizione degli autovalori, in particolare per l'apprendimento automatico. Nell'apprendimento automatico è facile finire con regressori altamente collineari. SVD funziona meglio in questi casi.
Ecco il codice Python per dimostrare il punto. Ho creato una matrice di dati altamente collineare, ho ottenuto la sua matrice di covarianza e ho cercato di ottenere gli autovalori di quest'ultima. SVD funziona ancora, mentre in questo caso la normale decomposizione degli automi non riesce.
import numpy as np
import math
from numpy import linalg as LA
np.random.seed(1)
# create the highly collinear series
T = 1000
X = np.random.rand(T,2)
eps = 1e-11
X[:,1] = X[:,0] + eps*X[:,1]
C = np.cov(np.transpose(X))
print('Cov: ',C)
U, s, V = LA.svd(C)
print('SVDs: ',s)
w, v = LA.eig(C)
print('eigen vals: ',w)
Produzione:
Cov: [[ 0.08311516 0.08311516]
[ 0.08311516 0.08311516]]
SVDs: [ 1.66230312e-01 5.66687522e-18]
eigen vals: [ 0. 0.16623031]
Aggiornare
In risposta al commento di Federico Poloni, ecco il codice con test di stabilità di SVD vs Eig su 1000 campioni casuali della stessa matrice sopra. In molti casi Eig mostra 0 un piccolo valore di autov, che porterebbe alla singolarità della matrice, e SVD non lo fa qui. SVD è circa due volte più preciso su una determinazione del valore di un piccolo autovena, che può essere o meno importante a seconda del problema.
import numpy as np
import math
from scipy.linalg import toeplitz
from numpy import linalg as LA
np.random.seed(1)
# create the highly collinear series
T = 100
p = 2
eps = 1e-8
m = 1000 # simulations
err = np.ones((m,2)) # accuracy of small eig value
for j in range(m):
u = np.random.rand(T,p)
X = np.ones(u.shape)
X[:,0] = u[:,0]
for i in range(1,p):
X[:,i] = eps*u[:,i]+u[:,0]
C = np.cov(np.transpose(X))
U, s, V = LA.svd(C)
w, v = LA.eig(C)
# true eigen values
te = eps**2/2 * np.var(u[:,1])*(1-np.corrcoef(u,rowvar=False)[0,1]**2)
err[j,0] = s[p-1] - te
err[j,1] = np.amin(w) - te
print('Cov: ',C)
print('SVDs: ',s)
print('eigen vals: ',w)
print('true small eigenvals: ',te)
acc = np.mean(np.abs(err),axis=0)
print("small eigenval, accuracy SVD, Eig: ",acc[0]/te,acc[1]/te)
Produzione:
Cov: [[ 0.09189421 0.09189421]
[ 0.09189421 0.09189421]]
SVDs: [ 0.18378843 0. ]
eigen vals: [ 1.38777878e-17 1.83788428e-01]
true small eigenvals: 4.02633695086e-18
small eigenval, accuracy SVD, Eig: 2.43114702041 3.31970128319
X1= uX2= u + ε v
u , v( σ21σ21+ ε ρ σ1σ2σ21+ ε ρ σ1σ2σ21+ 2 ε ρ σ1σ2+ ε2σ22σ2)
σ21, σ22, ρ - varianze delle uniformi e coefficiente di correlazione tra loro.
λ = 12( σ22ε2- σ42ε4+ 4 σ32ρ σ1ε3+ 8 σ22ρ2σ21ε2+ 8 σ2ρ σ31ε + 4 σ41-------------------------------------√+ 2 σ2ρ σ1ε + 2 σ21)
Il piccolo autovalore non può essere calcolato semplicemente collegando il
ε in formula a causa della precisione limitata, quindi è necessario Taylor espanderlo:
λ ≈ σ22ε2( 1 - ρ2) / 2
io corro j = 1 , … , m simulazioni delle realizzazioni della matrice di dati, calcolare gli autovalori della matrice di covarianza simulata λ^je ottenere gli errori ej= λ - λ^j.