Credo che ciò a cui stai arrivando nella tua domanda riguardi il troncamento dei dati utilizzando un numero inferiore di componenti principali (PC). Per tali operazioni, penso che la funzione prcomp
sia più illustrativa in quanto è più facile visualizzare la moltiplicazione della matrice utilizzata nella ricostruzione.
Innanzitutto, dai un set di dati sintetico, Xt
esegui il PCA (in genere centreresti i campioni per descrivere i PC relativi a una matrice di covarianza:
#Generate data
m=50
n=100
frac.gaps <- 0.5 # the fraction of data with NaNs
N.S.ratio <- 0.25 # the Noise to Signal ratio for adding noise to data
x <- (seq(m)*2*pi)/m
t <- (seq(n)*2*pi)/n
#True field
Xt <-
outer(sin(x), sin(t)) +
outer(sin(2.1*x), sin(2.1*t)) +
outer(sin(3.1*x), sin(3.1*t)) +
outer(tanh(x), cos(t)) +
outer(tanh(2*x), cos(2.1*t)) +
outer(tanh(4*x), cos(0.1*t)) +
outer(tanh(2.4*x), cos(1.1*t)) +
tanh(outer(x, t, FUN="+")) +
tanh(outer(x, 2*t, FUN="+"))
Xt <- t(Xt)
#PCA
res <- prcomp(Xt, center = TRUE, scale = FALSE)
names(res)
Nei risultati oppure prcomp
, è possibile visualizzare il PC ( res$x
), gli autovalori ( res$sdev
) che forniscono informazioni sulla grandezza di ciascun PC e i caricamenti ( res$rotation
).
res$sdev
length(res$sdev)
res$rotation
dim(res$rotation)
res$x
dim(res$x)
Quadrando gli autovalori, si ottiene la varianza spiegata da ciascun PC:
plot(cumsum(res$sdev^2/sum(res$sdev^2))) #cumulative explained variance
Infine, puoi creare una versione troncata dei tuoi dati utilizzando solo i PC (importanti) principali:
pc.use <- 3 # explains 93% of variance
trunc <- res$x[,1:pc.use] %*% t(res$rotation[,1:pc.use])
#and add the center (and re-scale) back to data
if(res$scale != FALSE){
trunc <- scale(trunc, center = FALSE , scale=1/res$scale)
}
if(res$center != FALSE){
trunc <- scale(trunc, center = -1 * res$center, scale=FALSE)
}
dim(trunc); dim(Xt)
Puoi vedere che il risultato è una matrice di dati leggermente più fluida, con caratteristiche su piccola scala filtrate:
RAN <- range(cbind(Xt, trunc))
BREAKS <- seq(RAN[1], RAN[2],,100)
COLS <- rainbow(length(BREAKS)-1)
par(mfcol=c(1,2), mar=c(1,1,2,1))
image(Xt, main="Original matrix", xlab="", ylab="", xaxt="n", yaxt="n", breaks=BREAKS, col=COLS)
box()
image(trunc, main="Truncated matrix (3 PCs)", xlab="", ylab="", xaxt="n", yaxt="n", breaks=BREAKS, col=COLS)
box()
Ed ecco un approccio molto semplice che puoi fare al di fuori della funzione prcomp:
#alternate approach
Xt.cen <- scale(Xt, center=TRUE, scale=FALSE)
C <- cov(Xt.cen, use="pair")
E <- svd(C)
A <- Xt.cen %*% E$u
#To remove units from principal components (A)
#function for the exponent of a matrix
"%^%" <- function(S, power)
with(eigen(S), vectors %*% (values^power * t(vectors)))
Asc <- A %*% (diag(E$d) %^% -0.5) # scaled principal components
#Relationship between eigenvalues from both approaches
plot(res$sdev^2, E$d) #PCA via a covariance matrix - the eigenvalues now hold variance, not stdev
abline(0,1) # same results
Ora, decidere quali PC conservare è una domanda separata, una questione a cui ero interessato qualche tempo fa . Spero che sia d'aiuto.