@amoeba đã có câu trả lời tuyệt vời cho các câu hỏi PCA, bao gồm câu hỏi này liên quan đến SVD với PCA. Trả lời cho câu hỏi chính xác của bạn, tôi sẽ đưa ra ba điểm:
- về mặt toán học, không có sự khác biệt cho dù bạn tính PCA trực tiếp trên ma trận dữ liệu hay trên ma trận hiệp phương sai của nó
- sự khác biệt hoàn toàn là do độ chính xác và độ phức tạp của số. Áp dụng áp dụng SVD trực tiếp vào ma trận dữ liệu ổn định hơn về số lượng so với ma trận hiệp phương sai
- SVD có thể được áp dụng cho ma trận hiệp phương sai để thực hiện PCA hoặc thu được các giá trị riêng, trên thực tế, đó là phương pháp ưa thích của tôi để giải quyết các vấn đề bản địa
Nó chỉ ra rằng SVD ổn định hơn các thủ tục xác định vị trí eigenvalue điển hình, đặc biệt, đối với học máy. Trong học máy, thật dễ dàng để kết thúc với các hồi quy cộng tuyến cao. SVD hoạt động tốt hơn trong những trường hợp này.
Đây là mã Python để demo điểm. Tôi đã tạo ra một ma trận dữ liệu cộng tuyến cao, có ma trận hiệp phương sai của nó và cố gắng đạt được các giá trị riêng sau này. SVD vẫn hoạt động, trong khi phân tách eigen thông thường thất bại trong trường hợp này.
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)
Đầu ra:
Cov: [[ 0.08311516 0.08311516]
[ 0.08311516 0.08311516]]
SVDs: [ 1.66230312e-01 5.66687522e-18]
eigen vals: [ 0. 0.16623031]
Cập nhật
Trả lời nhận xét của Federico Poloni, đây là đoạn mã kiểm tra độ ổn định của SVD so với Eig trên 1000 mẫu ngẫu nhiên của cùng một ma trận ở trên. Trong nhiều trường hợp, Eig hiển thị 0 giá trị eigen nhỏ, điều này sẽ dẫn đến tính đơn lẻ của ma trận và SVD không làm điều đó ở đây. SVD chính xác hơn gấp đôi so với xác định giá trị bản địa nhỏ, điều này có thể hoặc không quan trọng tùy thuộc vào vấn đề của bạn.
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)
Đầu ra:
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
Ở đây mã mã hoạt động. Thay vì tạo ma trận hiệp phương sai ngẫu nhiên để kiểm tra các thói quen, tôi đang tạo ma trận dữ liệu ngẫu nhiên với hai biến:
x1=ux2=u+εv
u,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