Andrew Ng가 PCA를 수행하기 위해 공분산 행렬의 EIG가 아닌 SVD를 선호하는 이유는 무엇입니까? 스탠포드 NLP 과정에서 cs224n의 첫 번째

Andrew Ng의 Coursera 코스 및 기타 자료에서 PCA를 공부하고 있습니다. 스탠포드 NLP 과정에서 cs224n의 첫 번째 과제Andrew Ng강의 비디오에서 공분산 행렬의 고유 벡터 분해 대신 특이 값 분해를 수행하며 Ng는 SVD가 고유 분해보다 수치 적으로 더 안정적이라고 말합니다.

PCA의 경우 (m,n)크기의 공분산 행렬이 아닌 크기 의 데이터 행렬의 SVD를 수행해야 (n,n)합니다. 공분산 행렬의 고유 벡터 분해.

왜 데이터 행렬이 아닌 공분산 행렬의 SVD를 수행합니까?



답변

amoeba는 이미 의견에 좋은 대답을했지만 공식적인 주장을 원한다면 여기에 간다.

행렬의 특이 값 분해 = U Σ V T 의 열, V는 의 고유 벡터이다 T 그리고 대각선 엔트리 Σ 있다 제곱근 그 고유의, 즉 σ I I =

에이

A=UΣVT

V

ATA

Σ

.

σii=λi(ATA)

아시다시피 주성분은 경험적 공분산 행렬의 고유 벡터 공간에 대한 변수의 직교 투영입니다 . 성분의 분산은 고유 값λi(1

1n1ATA

.

λi(1n1ATA)

B v = λ v가 되도록 정사각 행렬 , α R 및 벡터 v를 고려하십시오 . 그때

B

αR

v

Bv=λV


  1. Bkv=λ케이V


  2. λ(α)=αλ()

S = 1을 정의하자. SVD의S는의 계산한다 eigendecompositionSTS=1

에스=11에이에이

에스

를 산출

STS=1(n1)2ATAATA

  1. 의 고유 벡터 속성 1의 것이며, T
    (ATA)TATA=ATAATA

    ATA

  2. 제곱근 의 고유의 , 특성 2, 1, 2는 다시
    1(n1)2ATAATA

    .

    1(n1)2λi(ATAATA)=1(n1)2λi2(ATA)=1n1λi(ATA)=λi(1n1ATA)

oil!

수치 안정성과 관련하여, 사용 된 알고리즘이 무엇인지 알아 내야합니다. 당신이 그것에 달려 있다면, 나는 이것이 numpy에 의해 사용되는 LAPACK 루틴이라고 생각합니다 :

업데이트 : 안정성에서 SVD 구현은 분할 및 정복 접근법을 사용하는 것처럼 보이지만 고유 분해는 일반 QR 알고리즘을 사용합니다. 기관에서 제공하는 관련 SIAM 논문 (비난 연구 삭감)에 액세스 할 수 없지만 SVD 루틴이 더 안정적이라는 평가를 뒷받침 할 수있는 것을 발견했습니다.

에서

Nakatsukasa, Yuji 및 Nicholas J. Higham. “대칭 고유 값 분해 및 SVD를위한 안정적이고 효율적인 스펙트럼 분할 및 정복 알고리즘.” 과학 컴퓨팅에 관한 SIAM Journal 35.3 (2013) : A1325-A1349.

그들은 다양한 고유 값 알고리즘의 안정성을 비교하며, 분할 및 정복 접근법 (실험 중 하나에서 numpy와 동일한 방식을 사용합니다!)이 QR 알고리즘보다 더 안정적인 것으로 보입니다. 이것은 D & C 방법이 더 안정적이라는 다른 주장과 함께 Ng의 선택을 뒷받침합니다.


답변

@amoeba 포함 PCA 질문에 훌륭한 대답했다 이 한 PCA에 SVD의 관계에있다. 정확한 질문에 대답하면 세 가지 점을 알려 드리겠습니다.

  • 수학적으로 데이터 행렬에서 직접 또는 공분산 행렬에서 PCA를 계산하는지 여부에는 차이가 없습니다.
  • 그 차이는 순전히 수치 정밀도와 복잡성 때문입니다. SVD를 데이터 행렬에 직접 적용하는 것은 공분산 행렬보다 수치 적으로 더 안정적입니다.
  • SVD를 공분산 행렬에 적용하여 PCA를 수행하거나 고유 값을 얻을 수 있습니다. 실제로 고유 문제를 해결하는 것이 가장 좋아하는 방법입니다.

SVD는 특히 머신 러닝의 일반적인 고유 값 감소 절차보다 안정적입니다. 머신 러닝에서는 공 선형 회귀 분석을 쉽게 수행 할 수 있습니다. 이 경우 SVD가 더 잘 작동합니다.

요점을 시연하는 Python 코드가 있습니다. 나는 매우 공선적인 데이터 행렬을 만들고 공분산 행렬을 가져 와서 후자의 고유 값을 얻으려고했습니다. SVD는 여전히 작동하지만이 경우 일반적인 고유 분해는 실패합니다.

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)

산출:

Cov:  [[ 0.08311516  0.08311516]
 [ 0.08311516  0.08311516]]
SVDs:  [  1.66230312e-01   5.66687522e-18]
eigen vals:  [ 0.          0.16623031]

최신 정보

Federico Poloni의 의견에 따라 SVD와 Eig의 안정성 테스트가 위의 동일한 행렬의 무작위 샘플 1000 개에 대한 코드가 있습니다. 많은 경우에, Eig는 0의 작은 고유 값을 보여주는데, 이는 행렬의 특이성을 초래할 것입니다. 그리고 SVD는 여기서하지 않습니다. SVD는 작은 고유 값 결정에서 두 배 정도 더 정확하며, 문제에 따라 중요하거나 중요하지 않을 수 있습니다.

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)

산출:

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

(σ12σ12+ερσ1σ2σ12+ερσ1σ2σ12+2ερσ1σ2+ε2σ22σ2)

σ12,σ22,ρ

– 유니폼과 그들 사이의 상관 관계 coeffient의 편차를.

λ=12(σ22ε2σ24ε4+4σ23ρσ1ε3+8σ22ρ2σ12ε2+8σ2ρσ13ε+4σ14+2σ2ρσ1ε+2σ12)


The small eigenvalue can’t be calculated by simply plugging the

ε

into formula due to limited precision, so you need to Taylor expand it:

λσ22ε2(1ρ2)/2

I run

j=1,,m

simulations of the realizations of the data matrix, calculate the eigenvalues of the simulated covariance matrix

λ^j

, and obtain the errors

ej=λλ^j

.


답변

For Python users, I’d like to point out that for symmetric matrices (like the covariance matrix), it is better to use numpy.linalg.eigh function instead of a general numpy.linalg.eig function.

eigh is 9-10 times faster than eig on my computer (regardless of matrix size) and has better accuracy (based on @Aksakal’s accuracy test).

I am not convinced with the demonstration of the accuracy benefit of SVD with small eigenvalues. @Aksakal’s test is 1-2 orders of magnitude more sensitive to random state than to the algorithm (try plotting all errors instead of reducing them to one absolute maximum). It means that small errors in the covariance matrix will have a greater effect on accuracy than the choice of an eigendecomposition algorithm. Also, this is not related to the main question, which is about PCA. The smallest components are ignored in PCA.

A similar argument can be made about numerical stability. If I have to use the covariance matrix method for PCA, I would decompose it with eigh instead of svd. If it fails (which has not been demonstrated here yet), then it is probably worth rethinking the problem that you are trying to solve before starting to look for a better algorithm.


답변

질문의 마지막 부분에 답하기 위해 “왜 그들은 데이터 행렬이 아닌 공분산 행렬의 SVD를 수행합니까?” 나는 그것이 성능 및 저장상의 이유라고 생각합니다. 일반적으로

매우 큰 숫자가 될지라도

크다, 우리는 기대할 것이다

.

공분산 행렬을 계산 한 다음 SVD를 수행하는 것은 동일한 결과를 위해 이러한 조건에서 전체 데이터 행렬에 대한 SVD를 계산하는 것보다 훨씬 빠릅니다.

상당히 작은 값이라도 성능 향상은 수천 배 (밀리 초 대 초)입니다. Matlab을 사용하여 비교하기 위해 컴퓨터에서 몇 가지 테스트를 실행했습니다.
enter image description here

그것은 CPU 시간 일 뿐이지 만 스토리지 요구는 그다지 중요하지 않습니다. Matlab에서 백만 x 천 개의 매트릭스에서 SVD를 시도하면 7.4TB의 작업 배열 크기가 필요하기 때문에 기본적으로 오류가 발생합니다.


답변