@amoeba a eu d'excellentes réponses aux questions de l'ACP, y compris celle-ci sur la relation entre SVD et PCA. En réponse à votre question exacte, je ferai trois remarques:
- mathématiquement, il n'y a pas de différence si vous calculez PCA directement sur la matrice de données ou sur sa matrice de covariance
- la différence est purement due à la précision et à la complexité numériques. L'application de l'application de SVD directement à la matrice de données est numériquement plus stable qu'à la matrice de covariance
- SVD peut être appliqué à la matrice de covariance pour effectuer l'ACP ou obtenir des valeurs propres, en fait, c'est ma méthode préférée pour résoudre les problèmes propres
Il s'avère que SVD est plus stable que les procédures de décomposition à valeurs propres typiques, en particulier, pour l'apprentissage automatique. Dans l'apprentissage automatique, il est facile de se retrouver avec des régresseurs hautement colinéaires. SVD fonctionne mieux dans ces cas.
Voici du code Python pour démontrer le point. J'ai créé une matrice de données hautement colinéaire, obtenu sa matrice de covariance et essayé d'obtenir les valeurs propres de cette dernière. SVD fonctionne toujours, alors que la décomposition propre ordinaire échoue dans ce cas.
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)
Sortie:
Cov: [[ 0.08311516 0.08311516]
[ 0.08311516 0.08311516]]
SVDs: [ 1.66230312e-01 5.66687522e-18]
eigen vals: [ 0. 0.16623031]
Mise à jour
En réponse au commentaire de Federico Poloni, voici le code avec les tests de stabilité de SVD vs Eig sur 1000 échantillons aléatoires de la même matrice ci-dessus. Dans de nombreux cas, Eig affiche 0 petite valeur propre, ce qui conduirait à la singularité de la matrice, et SVD ne le fait pas ici. La SVD est environ deux fois plus précise sur une petite détermination de valeur propre, qui peut être importante ou non en fonction de votre problème.
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)
Sortie:
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
Ici, le code fonctionne. Au lieu de générer la matrice de covariance aléatoire pour tester les routines, je génère la matrice de données aléatoire avec deux variables:
où u , v - variables aléatoires uniformes indépendantes. Ainsi, la matrice de covariance est
( σ 2 1 σ 2 1 + ε ρ σ 1 σ 2 σ 2 1 + ε ρ σ 1 σ 2 σ 2 1 + 2 ε ρ σ 1 σ 2 + ε 2 σ 2 2 σ 2 )
x1=ux2=u+εv
u,v(σ21σ21+ερσ1σ2σ21+ερσ1σ2σ21+2ερσ1σ2+ε2σ22σ2)
où
- variances des uniformes et coefficients de corrélation entre eux.
σ21,σ22,ρ
Sa plus petite valeur propre:
λ=12(σ22ε2−σ42ε4+4σ32ρσ1ε3+8σ22ρ2σ21ε2+8σ2ρσ31ε+4σ41−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−√+2σ2ρσ1ε+2σ21)
ελ≈σ22ε2(1−ρ2)/2
j=1,…,mλ^jej=λ−λ^j