@amoeba memiliki jawaban yang sangat baik untuk pertanyaan PCA, termasuk yang ini tentang hubungan SVD ke PCA. Menjawab pertanyaan persis Anda, saya akan membuat tiga poin:
- Secara matematis tidak ada perbedaan apakah Anda menghitung PCA pada matriks data secara langsung atau pada matriks kovariannya
- perbedaannya murni karena presisi numerik dan kompleksitas. Menerapkan menerapkan SVD langsung ke matriks data secara numerik lebih stabil daripada ke matriks kovarians
- SVD dapat diterapkan ke matriks kovarians untuk melakukan PCA atau mendapatkan nilai eigen, pada kenyataannya, ini adalah metode favorit saya untuk memecahkan masalah eigen
Ternyata SVD lebih stabil daripada prosedur dekomoposisi nilai eigen tipikal, terutama, untuk pembelajaran mesin. Dalam pembelajaran mesin, mudah untuk berakhir dengan regresi yang sangat kolinear. SVD bekerja lebih baik dalam kasus ini.
Berikut kode Python untuk menunjukkan maksudnya. Saya membuat matriks data yang sangat collinear, mendapatkan matriks kovariannya dan mencoba untuk mendapatkan nilai eigen dari yang terakhir. SVD masih berfungsi, sementara dekomposisi eigen biasa gagal dalam kasus ini.
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)
Keluaran:
Cov: [[ 0.08311516 0.08311516]
[ 0.08311516 0.08311516]]
SVDs: [ 1.66230312e-01 5.66687522e-18]
eigen vals: [ 0. 0.16623031]
Memperbarui
Menjawab komentar Federico Poloni, inilah kode dengan pengujian stabilitas SVD vs Eig pada 1000 sampel acak dari matriks yang sama di atas. Dalam banyak kasus Eig menunjukkan 0 nilai eigen kecil, yang akan menyebabkan singularitas matriks, dan SVD tidak melakukannya di sini. SVD sekitar dua kali lebih tepat pada penentuan nilai eigen kecil, yang mungkin atau mungkin tidak penting tergantung pada masalah Anda.
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)
Keluaran:
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
kamu , v( σ21σ21+ ε ρ σ1σ2σ21+ ε ρ σ1σ2σ21+ 2 ε ρ σ1σ2+ ε2σ22σ2)
σ21, σ22, ρ
λ = 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