Perché PCA dei dati mediante SVD dei dati?


22

Questa domanda riguarda un modo efficiente per calcolare i componenti principali.

  1. Molti testi su PCA lineare sostengono l'uso della decomposizione a valore singolare dei dati casewise . Cioè, se abbiamo dati e vogliamo sostituire le variabili (le sue colonne ) con i componenti principali, facciamo SVD: , valori singolari (radici quadrate degli autovalori) che occupano la diagonale principale di , autovettori di destra sono la matrice di rotazione ortogonale delle variabili degli assi in componenti degli assi, gli autovettori di sinistra sono come , solo per i casi. Possiamo quindi calcolare i valori dei componenti come .XX=USVSVUVC=XV=US

  2. Un altro modo di fare PCA di variabili è attraverso la decomposizione della matrice quadrata (cioè può essere correlazioni o covarianze ecc., Tra le variabili). La decomposizione può essere decomposizione di autigeni o decomposizione di valore singolare: con matrice semidefinita positiva simmetrica quadrata, daranno lo stesso risultato con autovalori della diagonale di e come descritto in precedenza. I valori dei componenti saranno .R=XXR R=VLVLVC=XV

Ora, la mia domanda: se data è una matrice grande, e il numero di casi è (che è spesso un caso) molto maggiore del numero di variabili, allora la via (1) dovrebbe essere molto più lenta della via (2 ), perché way (1) applica un algoritmo piuttosto costoso (come SVD) a una matrice grande; calcola e memorizza enormi matrici cui non abbiamo davvero bisogno nel nostro caso (il PCA delle variabili). Se è così, allora perché così tanti libri di testo sembrano difendere o menzionare solo il modo (1)? Forse è efficiente e mi manca qualcosa?XU


2
In generale siamo interessati solo ai pochi componenti principali che spiegano la maggior parte della varianza. È possibile eseguire un SVD ridotto; per esempio, se è di dimensione dove poi 's funzione calcolerà solo il primo destro e sinistro vettori singolari di default. XN×pp<<NRsvdp
M. Berk,

1
@ M.Berk: , tuttavia, è lo stesso in entrambi gli approcci: producono risultati equivalenti (uguali fino a firmare le modifiche). Inoltre, ad esempio, R calcola solo se richiesto. pC
cbeleites supporta Monica il

Hai riferimenti per way (1)? Sono a conoscenza del fatto che PCA viene implementato tramite SVD sulla matrice di covarianza (ovvero la via 2), in quanto ciò evita alcuni problemi numerici e si ridimensiona in modo irreversibile con la dimensionalità, non con la dimensione del set di dati. Way (1) Definirei SVD, non affatto PCA. L'ho visto solo in un puro contesto SVD, dove in realtà non si sarebbe eseguita una decomposizione completa.
Anony-Mousse

@ Anony-Mousse, solo uno da menzionare, in Joliffe, Principal component analysis, 2nd ed.realtà, Joliffe descrive entrambi i modi, ma nel capitolo principale su PCA dice solo il modo 1, per quanto io possa ricordare.
ttnphns,

@ Anony-Mousse, Way 1 per me è importante dal punto di vista teorico perché mostra chiaramente come PCA è direttamente correlato alla semplice analisi della corrispondenza .
ttnphns

Risposte:


7

Ecco il mio 2ct sull'argomento

  • La lezione di chemiometria in cui ho appreso per la prima volta PCA utilizzava la soluzione (2), ma non era orientata numericamente e la mia lezione di numerica era solo un'introduzione e non ho discusso di SVD per quanto ricordo.

  • Se ho capito bene Holmes: SVD veloce per matrici su larga scala , la tua idea è stata usata per ottenere un SVD computazionalmente veloce di matrici lunghe.
    Ciò significherebbe che una buona implementazione SVD potrebbe seguire internamente (2) se incontra matrici adatte (non so se ci sono ancora migliori possibilità). Ciò significherebbe che per un'implementazione di alto livello è meglio usare SVD (1) e lasciarlo al BLAS per occuparsi dell'algoritmo da usare internamente.

  • Controllo pratico rapido: lo svd di OpenBLAS non sembra fare questa distinzione, su una matrice di 5e4 x 100, svd (X, nu = 0)assume una media di 3,5 s, mentre svd (crossprod (X), nu = 0)richiede 54 ms (chiamato da R con microbenchmark).
    La quadratura degli autovalori ovviamente è veloce e fino a quel momento i risultati di entrambe le chiamate sono equivalenti.

    timing  <- microbenchmark (svd (X, nu = 0), svd (crossprod (X), nu = 0), times = 10)
    timing
    # Unit: milliseconds
    #                      expr        min         lq    median         uq        max neval
    #            svd(X, nu = 0) 3383.77710 3422.68455 3507.2597 3542.91083 3724.24130    10
    # svd(crossprod(X), nu = 0)   48.49297   50.16464   53.6881   56.28776   59.21218    10
    

aggiornamento: dai un'occhiata a Wu, W .; Massart, D. & de Jong, S .: Algoritmi PCA del kernel per dati di grandi dimensioni. Parte I: Teoria e algoritmi, chemiometria e sistemi di laboratorio intelligenti, 36, 165 - 172 (1997). DOI: http://dx.doi.org/10.1016/S0169-7439(97)00010-5

Questo articolo discute le proprietà numeriche e computazionali di 4 diversi algoritmi per PCA: SVD, decomposizione di autovene (EVD), NIPALS e POWER.

Sono correlati come segue:

computes on      extract all PCs at once       sequential extraction    
X                SVD                           NIPALS    
X'X              EVD                           POWER

Il contesto del documento è ampio e funziona su X X (kernel PCA) - questa è esattamente la situazione opposta a quella di cui si chiede. Quindi, per rispondere alla tua domanda sul comportamento a matrice lunga, devi scambiare il significato di "kernel" e "classico".X(30×500)XX

confronto delle prestazioni

Non sorprende che EVD e SVD cambino posto a seconda che vengano utilizzati gli algoritmi classici o del kernel. Nel contesto di questa domanda ciò significa che l'uno o l'altro può essere migliore a seconda della forma della matrice.

XXsvd ()


    > sessionInfo ()
    R version 3.0.2 (2013-09-25)
    Platform: x86_64-pc-linux-gnu (64-bit)

    locale:
     [1] LC_CTYPE=de_DE.UTF-8       LC_NUMERIC=C               LC_TIME=de_DE.UTF-8        LC_COLLATE=de_DE.UTF-8     LC_MONETARY=de_DE.UTF-8   
     [6] LC_MESSAGES=de_DE.UTF-8    LC_PAPER=de_DE.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
    [11] LC_MEASUREMENT=de_DE.UTF-8 LC_IDENTIFICATION=C       

    attached base packages:
    [1] stats     graphics  grDevices utils     datasets  methods   base     

    other attached packages:
    [1] microbenchmark_1.3-0

loaded via a namespace (and not attached):
[1] tools_3.0.2

$ dpkg --list libopenblas*
[...]
ii  libopenblas-base              0.1alpha2.2-3                 Optimized BLAS (linear algebra) library based on GotoBLAS2
ii  libopenblas-dev               0.1alpha2.2-3                 Optimized BLAS (linear algebra) library based on GotoBLAS2

Quindi, i tuoi test (3,5 secondi contro 54 msec) supportano la mia linea secondo cui "il modo 1" è notevolmente più lento. Destra?
ttnphns,

1
@ttnphns: si. Ma come svd è fornito dal BLAS che potrebbe essere diverso con un BLAS diverso. Mi sarei aspettato che un buon BLAS ottimizzato facesse qualcosa del genere. Tuttavia, non sembra essere il caso di OpenBLAS. Sono troppo pigro per controllare altri BLAS, ma forse alcune persone potrebbero controllare i loro altri BLAS, quindi scopriamo quali sono ottimizzati per questo caso e quali no. (Ho inviato un'e-mail allo sviluppatore OpenBLAS e gli ho inviato un collegamento a questa domanda, quindi forse può aggiungere alcune informazioni, ad esempio motivi per non passare l'algoritmo a svd (X'X)per le matrici lunghe.)
cbeleites supporta Monica

XXn<pXXun+1=XXun/||XXun||v1XXXX×(Xun)

XXT

Stavo parlando del tuo aggiornamento, in cui è coinvolto Nipals. Confermo che Nipals non è coinvolto nell'SVD di Lapack. A proposito del tuo esperimento di riferimento, anche qualcosa di simile microbenchmark(X <- matrix(rnorm(5e6), ncol=100), Y <- t(X), svd(X), svd(Y), control=list(order="inorder"), times = 5)può essere interessante.
Elvis,

18

SVD è più lento ma è spesso considerato il metodo preferito a causa della sua maggiore precisione numerica.

X1n1XXXXnp

Ecco ciò che è scritto nel MATLAB di pca()funzione di aiuto :

Algoritmo del componente principale che pcautilizza per eseguire l'analisi del componente principale [...]:

'svd': impostazione predefinita. Decomposizione del valore singolare (SVD) di X.

np

L'ultima frase evidenzia il fondamentale compromesso di precisione della velocità che è in gioco qui.

1000×100

X = randn([1000 100]);

tic; svd(X); toc         %// Elapsed time is 0.004075 seconds.
tic; svd(X'); toc        %// Elapsed time is 0.011194 seconds.
tic; eig(X'*X); toc      %// Elapsed time is 0.001620 seconds.
tic; eig(X*X'); toc;     %// Elapsed time is 0.126723 seconds.

npXX

XXXX

X=(111ϵ000ϵ000ϵ),
3+ϵ2ϵ2ϵ2ϵ=105
eps = 1e-5;
X = [1 1 1; eye(3)*eps];
display(['Squared sing. values of X: ' num2str(sort(svd(X),'descend').^2')])
display(['Eigenvalues of X''*X:       ' num2str(sort(eig(X'*X),'descend')')])

ottenere risultati identici:

Squared sing. values of X: 3       1e-10       1e-10
Eigenvalues of X'*X:       3       1e-10       1e-10

ϵ=1010

Squared sing. values of X: 3       1e-20       1e-20
Eigenvalues of X'*X:       3           0 -3.3307e-16

XX

Vorrei aggiungere che si è spesso felici di ignorare questa potenziale [minuscola] perdita di precisione e piuttosto usare il metodo più veloce.


1
XTX

Grazie per la risposta e per la completa considerazione di pro e contro.
ttnphns,

ameba, può essere che trovi il tempo di mostrare un esempio concreto in cui la stabilità numerica soffre di eig()approccio? (I lettori ne trarranno beneficio: c'è un punto di compromesso tra velocità e stabilità. Come si può decidere in una situazione pratica concreta?)
ttnphns

@ttnphns Ho riscritto l'intera risposta, fornendo un esempio concreto. Guarda.
ameba dice Reinstate Monica il

1
@amoeba, grazie mille per essere tornato e aver dato un esempio! Ho provato entrambi gli esempi epsilon in SPSS e ho ottenuto risultati come i tuoi tranne l'ultima riga: invece di 3 0 -3.3307e-16eigen in spss mi ha restituito 3 0 0. Sembra che la funzione abbia un valore di tolleranza integrato e fisso oltre il quale azzera. In questo esempio, la funzione appariva come per incidere sul nodo dell'instabilità numerica azzerando entrambi gli autovalori minuscoli, lo "0" e lo "-16".
ttnphns,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.