Andrew NgがPCAを行うために共分散行列のEIGではなくSVDを使用することを好むのはなぜですか?


29

Andrew NgのCourseraコースのPCAと他の資料を勉強しています。スタンフォードNLPコースcs224nの最初の課題、およびAndrew Ngの講義ビデオでは、共分散行列の固有ベクトル分解の代わりに特異値分解を行い、NgはSVDが固有分解よりも数値的に安定しているとさえ述べています。

私の理解では、PCAの場合、(m,n)サイズの共分散行列ではなく、サイズのデータ行列のSVDを行う必要があり(n,n)ます。そして、共分散行列の固有ベクトル分解。

なぜデータ行列ではなく共分散行列のSVDを行うのですか?


8
正方半正定行列(共分散行列など)の場合、固有値分解と特異値分解はまったく同じです。
アメーバは、モニカーを復活させる

5
私は、彼らがある意味、数学的に同じ。数値的には、実際には異なるアルゴリズムを使用している可能性があり、1つは別のアルゴリズムよりも安定している可能性があります(Ngが言うように)。これは、+ 1の詳細を知るのに興味深いでしょう。
アメーバは、モニカを復活させる

4
これに関するいくつかの情報はde.mathworks.com/matlabcentral/newsreader/view_thread/21268にあります。ただし、あるアルゴリズムが別のアルゴリズムよりも安定する理由についての説明は、非常に技術的なものになることに注意してください。
アメーバは、モニカを復活させる

2
x=randn(10000); x=x'*x; tic; eig(x); toc; tic; svd(x); toc;私のマシンのMatlab では、eig()に12秒、svd()に26秒を出力します。非常に遅い場合は、少なくともより安定している必要があります!:-)
アメーバは、モニカを復活させる

4
それは間違った理解に基づいてされる可能性があります:データ行列のSVDを行うには、ある使用するよりも、より安定しeigたりsvd、共分散行列に、しかし、私の知る限りでは使用しての間には大きな違いが存在しないeigか、svd彼らは---共分散行列には、両方の後方安定アルゴリズム。どちらかといえば、より少ない計算を行うため、より安定したeigにお金をかけます(両方とも最先端のアルゴリズムで実装されていると仮定)。
フェデリコポロニ

回答:


17

アメーバはすでにコメントで良い答えを出しましたが、正式な議論が必要な場合はここに行きます。

行列の特異値分解あるの列、の固有ベクトルであるとの対角エントリある平方根の固有値、すなわち。A = U Σ V T V A T A Σはσ のI iは = AA=うんΣVTVATAΣσ=λATA

ご存知のように、主成分は経験的共分散行列の固有ベクトルの空間への変数の正射影です。成分の分散は、固有値によって与えられます。λI11n1ATAλ1n1ATA

任意の正方行列、およびようなベクトルを考えます。それからα RのV BをV = λ VBαRvBv=λv

  1. Bkv=λkv
  2. λαB=αλB

定義しましょう。SVDの固有値分解計算する収率をSSTS=1S=1n1ATASSTS=1n12ATAATA

  1. 固有ベクトルプロパティ1のものであり、A T AATATATA=ATAATAATA
  2. の固有値の平方根。これはプロパティ、。1n12ATAATA1n12λATAATA=1n12λ2ATA=1n1λATA=λ1n1ATA

ほら!

数値の安定性に関しては、採用されたアルゴリズムが何であるかを理解する必要があります。あなたがそれまでなら、これらはnumpyが使用するLAPACKルーチンだと思います:

更新:安定性に関して、SVD実装は分割統治アプローチを使用しているようですが、固有分解ではプレーンQRアルゴリズムを使用しています。所属機関から関連するSIAM論文にアクセスすることはできません(非難調査の削減)が、SVDルーチンがより安定しているという評価をサポートする何かを見つけました。

中司、裕二、ニコラス・J・ハイアム。「対称固有値分解およびSVDのための安定した効率的なスペクトル分割および征服アルゴリズム。」SIAM Journal on Scientific Computing 35.3(2013):A1325-A1349。

彼らはさまざまな固有値アルゴリズムの安定性を比較しており、分割統治アプローチ(実験の1つでnumpyと同じアプローチを使用しています!)はQRアルゴリズムよりも安定しているようです。これは、D&Cの方法が実際にはより安定しているという他の主張とともに、Ngの選択を支持しています。


共分散のsvdと平均中心データのsvdから取得した固有値は同じではありません。
theGD

ただし、スコア、つまりX * V(Vは[U、S、V] = svd(x)またはsvd(covx)から取得されます)は同じです。
–GDの

1
cov(X)の@theGD固有値と(X)の特異値は同一ではありません。stats.stackexchange.com/ questions / 134282を参照してください。
アメーバは、モニカを復活させる

SIAMジャーナルへのアクセス不足に絶望する必要はありません。引用する論文はこちらです:opt.mist.iu-tokyo.ac.jp/~nakatsukasa/publishedpdf/pub13.pdf
Dima Pasechnik

2
@broncoAbiertoテクノロジー。レポートはこちら:cpsc.yale.edu/sites/default/files/files/tr932.pdf(おそらくcpsc.yale.edu/research/technical-reportsのタイトルにある「Symetric」のタイプミスのため、簡単に見つけることができません。/ 1992-technical-reports :
Dima Pasechnik

12

@amoebaは、SVDとPCAの関係に関するこの質問を含む、PCAの質問に対する優れた回答を持っています。あなたの正確な質問に答えるには、3つのポイントを挙げます。

  • 数学的には、データ行列で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のコメントに答えて、上記と同じマトリックスの1000個のランダムサンプルでのSVD対Eigの安定性テストのコードを示します。多くの場合、Eigは0の小さな固有値を示します。これにより、行列の特異性が生じますが、SVDはここでそれを行いません。SVDは、小さな固有値の決定で約2倍正確になります。これは、問題に応じて重要な場合と重要でない場合があります。

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

バツ1=あなたはバツ2=あなたは+εv
あなたはv
σ12σ12+ερσ1σ2σ12+ερσ1σ2σ12+2ερσ1σ2+ε2σ22σ2
σ12σ22ρ

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

j=1mλ^jej=λλ^j


4
はい。ただし、ここでOPは共分散行列に適用されるSVDとEIGの両方について質問しています。
アメーバは、

1
@ amoeba、SVDとPCAの関係を明らかにしました
Aksakal

これは良い答えです。ただし、svdは負の固有値があり、それらを確認したい場合は検出できないことを望みます(共分散行列が元ではなく、たとえば何らかの方法で平滑化または推定されているか、ペアワイズ削除から出ている場合)欠損値の))。さらに、cov行列のeigは、svdよりも少し高速のままです。
ttnphns

@ttnphns、非正定行列はもちろん問題です
-Aksakal

1
@ FedericoPoloni、FP演算について、正確な答えが分からないので、私は同意しません。この場合、このタスクに十分な精度で答えを知っています。2x2では、公平なポイントがあります。私は何かを考えます。
アクサカル

6

Pythonユーザーの場合、対称行列(共分散行列など)の場合numpy.linalg.eigh、一般的なnumpy.linalg.eig関数の代わりに関数を使用することをお勧めします。

eigheig(マトリックスサイズに関係なく)コンピューターよりも9〜10倍高速であり、精度が向上しています(@Aksakalの精度テストに基づく)。

固有値が小さいSVDの精度の利点を実証することはできません。@Aksakalのテストは、アルゴリズムよりもランダム状態に対して1〜2桁敏感です(1つの絶対最大値に減らすのではなく、すべてのエラーをプロットしてみてください)。これは、共分散行列の小さな誤差が固有分解アルゴリズムの選択よりも精度に大きな影響を与えることを意味します。また、これはPCAに関するメインの質問とは関係ありません。PCAでは最小のコンポーネントは無視されます。

数値の安定性についても同様の議論ができます。PCAに共分散行列法を使用する必要がある場合、のeigh代わりにを使用して分解しsvdます。失敗した場合(ここではまだ説明していません)、おそらく、より良いアルゴリズムを探し始める前に、解決しようとしている問題を再考する価値があります。



2

mnmn

共分散行列を計算してからその上でSVDを実行することは、同じ結果を得るために、これらの条件下で完全なデータ行列でSVDを計算するよりもはるかに高速です。

かなり小さな値であっても、パフォーマンスの向上は数千の要因です(ミリ秒対秒)。Matlabを使用して比較するために、マシンでいくつかのテストを実行しました。 ここに画像の説明を入力してください

それは単なるCPU時間ですが、ストレージのニーズは、それ以上ではないにしても重要です。Matlabで100万×1000のマトリックスでSVDを試みると、7.4TBの作業配列サイズが必要になるため、デフォルトでエラーになります。


これは、cov行列のEIGと共分散行列の SVDに関する質問には答えません。
アメーバは、モニカを復活させる

1
太字で強調されている最後の質問は、「なぜデータ行列ではなく共分散行列のSVDを行うのですか?」と述べています。私は答えました。
グラフ

冒頭の文を編集して、OPの質問のその部分に答えていたことを明確にします。私はそれがどのように紛らわしいのかわかります。ありがとう。
グラフ

Matlabで100万x 1000のマトリックスでSVDを試行すると、デフォルトでエラーになります。これにより、ストレージのサイズとパフォーマンスが大幅に向上します。
フェデリコポロニ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.