Come calcolare i componenti principali ruotati in varimax in R?


13

Ho eseguito PCA su 25 variabili e ho selezionato i migliori 7 PC utilizzando prcomp.

prc <- prcomp(pollutions, center=T, scale=T, retx=T)

Ho quindi fatto la rotazione varimax su quei componenti.

varimax7 <- varimax(prc$rotation[,1:7])

E ora vorrei varimax ruotare i dati ruotati da PCA (poiché non fa parte dell'oggetto varimax - solo la matrice dei carichi e la matrice di rotazione). Ho letto che per fare questo moltiplichi la trasposizione della matrice di rotazione per la trasposizione dei dati, quindi avrei fatto questo:

newData <- t(varimax7$rotmat) %*% t(prc$x[,1:7])

Ma ciò non ha senso poiché le dimensioni della matrice trasposte sopra sono rispettivamente e 7 × 16933 e quindi rimarrò con una matrice di sole 7 righe, anziché 16933 righe ... qualcuno sa cosa io sto sbagliando qui o quale dovrebbe essere la mia linea finale? Devo solo trasporre in seguito?7×77×16933716933

Risposte:


22

"Rotazioni" è un approccio sviluppato nell'analisi fattoriale; le rotazioni (come ad esempio varimax) vengono applicate ai carichi , non agli autovettori della matrice di covarianza. I caricamenti sono autovettori ridimensionati dalle radici quadrate dei rispettivi autovalori. Dopo la rotazione varimax, i vettori di caricamento non sono più ortogonali (anche se la rotazione è chiamata "ortogonale"), quindi non si può semplicemente calcolare le proiezioni ortogonali dei dati sulle direzioni di caricamento ruotate.

La risposta di FTusell presuppone che la rotazione di varimax sia applicata agli autovettori (non ai carichi). Questo sarebbe piuttosto non convenzionale. Per i dettagli, consultare il mio account dettagliato di PCA + varimax: PCA è seguito da una rotazione (come varimax) è ancora PCA? In breve, se osserviamo l'SVD della matrice di dati , quindi ruotare i caricamenti significa inserire R R per una matrice di rotazione R come segue: X = ( U R ) ( R S V ) .X=USVRRRX=(UR)(RSV).

Se la rotazione viene applicata ai caricamenti (come di solito), ci sono almeno tre semplici modi per calcolare i PC con rotazione varimax in R:

  1. Sono prontamente disponibili tramite la funzione psych::principal(dimostrando che questo è davvero l'approccio standard). Si noti che restituisce punteggi standardizzati , vale a dire che tutti i PC hanno una varianza di unità.

  2. È possibile utilizzare manualmente la varimaxfunzione per ruotare i carichi, quindi utilizzare i nuovi carichi ruotati per ottenere i punteggi; è necessario moltiplicare i dati con lo pseudo-inverso trasposto dei carichi ruotati (vedere le formule in questa risposta di @ttnphns ). Ciò produrrà anche punteggi standardizzati.

  3. Si può usare la varimaxfunzione per ruotare i carichi e quindi usare la $rotmatmatrice di rotazione per ruotare i punteggi standardizzati ottenuti con prcomp.

Tutti e tre i metodi producono lo stesso risultato:

irisX <- iris[,1:4]      # Iris data
ncomp <- 2

pca_iris_rotated <- psych::principal(irisX, rotate="varimax", nfactors=ncomp, scores=TRUE)
print(pca_iris_rotated$scores[1:5,])  # Scores returned by principal()

pca_iris        <- prcomp(irisX, center=T, scale=T)
rawLoadings     <- pca_iris$rotation[,1:ncomp] %*% diag(pca_iris$sdev, ncomp, ncomp)
rotatedLoadings <- varimax(rawLoadings)$loadings
invLoadings     <- t(pracma::pinv(rotatedLoadings))
scores          <- scale(irisX) %*% invLoadings
print(scores[1:5,])                   # Scores computed via rotated loadings

scores <- scale(pca_iris$x[,1:2]) %*% varimax(rawLoadings)$rotmat
print(scores[1:5,])                   # Scores computed via rotating the scores

Ciò produce tre uscite identiche:

1 -1.083475  0.9067262
2 -1.377536 -0.2648876
3 -1.419832  0.1165198
4 -1.471607 -0.1474634
5 -1.095296  1.0949536

Nota: la varimaxfunzione in R utilizza i normalize = TRUE, eps = 1e-5parametri per impostazione predefinita ( vedere la documentazione ). Uno potrebbe voler cambiare questi parametri (ridurre la epstolleranza e prendersi cura della normalizzazione di Kaiser) quando si confrontano i risultati con altri software come SPSS. Ringrazio @GottfriedHelms per avermi portato alla mia attenzione. [Nota: questi parametri funzionano quando vengono passati alla varimaxfunzione, ma non funzionano quando vengono passati alla psych::principalfunzione. Questo sembra essere un bug che verrà corretto.]


1
Lo vedo ora e penso che tu abbia ragione. Modificherò la mia risposta originale (o ne aggiungerò un'altra) per tracciare l'origine della discrepanza. Mi sono piaciute le risposte molto complete e illuminanti delle tue e di @ttnphns, fornendo spiegazioni dettagliate che di solito non si trovano nei libri.
F. Tusell,

@amoeba Sto provando a fare un varimax PCA + usando principal, prcompe princomp, ma i risultati risultanti / conclusioni dello studio sono molto diversi l'uno dall'altro. Per quello che ho capito, prcomp e princomp non restituiscono punteggi standardizzati né caricamenti. La mia domanda è: qual è l'approccio migliore? Voglio davvero risultati standardizzati? Il mio codice non è pca_iris <- prcomp(irisX, center=T, scale=T)seguito varimax(pca_iris$rotation)$loadingsesattamente come il tuo sopra?
JMarcelino,

@JMarcelino, no, il tuo codice esegue la rotazione varimax sugli autovettori, non sui caricamenti. Questo non è il modo in cui la rotazione di varimax viene generalmente compresa o applicata.
ameba dice che ripristini Monica il

1
@JMarcelino, stai chiedendo perché la matematica funziona come dico nel metodo n. 2? È semplice se hai familiarità con questo tipo di algebra lineare. PCA è la decomposizione SVD . Applicare una rotazione come varimax significa inserire R R per una matrice di rotazione R come segue: X = U R R S V . I carichi ruotati sono L = V S R / X=USVRRRX=URRSV , i punteggi standardizzati ruotati sonoT=URL=VSR/n1 , quindiX=TL. SaiXeL; come ottenereT? Bene, la risposta èT=X(L)+=X(L+). T=URn1
X=TL.
XLT
T=X(L)+=X(L+).
ameba dice di reintegrare Monica il

1
Ho ricevuto una risposta dal manutentore del pacchetto Prof. Revelle. Sembra essere un bug nella gestione dei parametri nella principalprocedura, che calcola sempre con la normalizzazione di Kaiser e eps = 1e-5. Finora non ci sono informazioni, perché su r-fiddle.org la versione funziona correttamente. Quindi dovremmo attendere gli aggiornamenti e dovrei eliminare tutti i commenti ormai obsoleti. ameba - sarebbe bene aggiornare di conseguenza l'osservazione nella tua risposta. Grazie per tutta la collaborazione!
Gottfried Helms

9

Devi usare la matrice $loadings, non $rotmat:

 x <- matrix(rnorm(600),60,10)
 prc <- prcomp(x, center=TRUE, scale=TRUE)
 varimax7 <- varimax(prc$rotation[,1:7])
 newData <- scale(x) %*% varimax7$loadings

La matrice $rotmatè la matrice ortogonale che produce i nuovi caricamenti da quelli non ruotati.

MODIFICA al 12 febbraio 2015:

n×mX

X=USVT
VXX
X=(UST)(TTVT)=UV
TVVUX(V)Tk<mkX
X(UkSk)(VkT)
X(UkSkTk)(TkTVkT)=UkVk
Vkk×nXVk, ma piuttosto dobbiamo ricorrere a una delle soluzioni descritte da @amoeba.

In altre parole, la soluzione che ho proposto è corretta solo nel caso particolare in cui sarebbe inutile e senza senso.

Grazie di cuore a @amoeba per avermi chiarito la questione; Ho vissuto con questo malinteso per anni.

SVLVSviTX (i=1,,m)vi=1. Penso che sia accettabile in entrambi i modi, e tutto il resto (come nell'analisi del biplot).

MODIFICA AGGIUNTIVA 12 febbraio 2015

VkVk(Vk)TX(Vk)TUk


1
Ah, vero. Mi sono confuso perché i caricamenti per il prcomp sono chiamati "rotazione", avrebbero dovuto leggere meglio l'aiuto. Dal momento che sto usando "center = TRUE, scale = TRUE" nel metodo prcomp, ciò significa che dovrei davvero centrare e ridimensionare i miei dati prima di moltiplicarli per i miei varimax $ loadings?
Scott,

1
Sì, buon punto, errore mio. Il centraggio non importerebbe, come se solo spostasse i punti, ma la scala dovrebbe essere la stessa usata per calcolare i componenti principali, che non sono invarianti al ridimensionamento.
F. Tusell,

2
Ho dimenticato di dire che potresti voler guardare la funzione factanal, se non l'hai già fatto. Esegue l'analisi dei fattori anziché i componenti principali, ma restituirà direttamente i punteggi.
F. Tusell,

2
-1. Credo che questa risposta non sia corretta e ho pubblicato la mia risposta per dimostrarla. Non è possibile ottenere punteggi ruotati mediante proiezione ortogonale sui carichi ruotati (perché non sono più ortogonali). Il modo più semplice per ottenere i punteggi corretti è usare psych::principal. [A parte questo, ho modificato la tua risposta per inserire il ridimensionamento, come discusso nei commenti sopra.]
ameba dice Reinstate Monica

1
Vkk×nV(TkTVkT)(VkTk)

0

Stavo cercando una soluzione che funzioni per PCA eseguita utilizzando ade4 .

Si prega di trovare la funzione qui sotto:

library(ade4)

irisX <- iris[,1:4]      # Iris data
ncomp <- 2
# With ade4
dudi_iris <- dudi.pca(irisX, scannf = FALSE, nf = ncomp)

rotate_dudi.pca <- function(pca, ncomp = 2) {

  rawLoadings <- as.matrix(pca$c1[,1:ncomp]) %*% diag(sqrt(pca$eig), ncomp, ncomp)
  pca$c1 <- rawLoadings
  pca$li <- scale(pca$li[,1:ncomp]) %*% varimax(rawLoadings)$rotmat

  return(pca)
} 
rot_iris <- rotate_dudi.pca(pca = dudi_iris, ncomp = ncomp)
print(rot_iris$li[1:5,])                   # Scores computed via rotating the scores
#>        [,1]       [,2]
#> 1 -1.083475 -0.9067262
#> 2 -1.377536  0.2648876
#> 3 -1.419832 -0.1165198
#> 4 -1.471607  0.1474634
#> 5 -1.095296 -1.0949536

Creato il 2020-01-14 dal pacchetto reprex (v0.3.0)

Spero che questo aiuto!


È necessario utilizzare questo spazio per una risposta.
Michael R. Chernick,

Mi è sembrato valido aggiungere una risposta per completezza. Come per questa domanda: stackoverflow.com/questions/6862742/draw-a-circle-with-ggplot2 . Sarò felice di spostare la mia proposta, se necessario.
Alain Danet,

Ho capito male perché sembrava che stavi facendo una correzione a un errore in una delle risposte. Vedo che si tratta di un'aggiunta per un determinato pacchetto software ad4. Cross Validated non esamina le domande o le risposte che riguardano esclusivamente il codice. Stack Overflow è dove vengono risolti i problemi del software.
Michael R. Chernick,
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.