Adicionarei uma resposta mais visual à sua pergunta, usando uma comparação de modelo nulo. O procedimento aleatoriamente embaralha os dados em cada coluna para preservar a variação geral enquanto a covariância entre variáveis (colunas) é perdida. Isso é realizado várias vezes e a distribuição resultante de valores singulares na matriz aleatória é comparada aos valores originais.
Eu uso em prcomp
vez de svd
para a decomposição da matriz, mas os resultados são semelhantes:
set.seed(1)
m <- matrix(runif(10000,min=0,max=25), nrow=100,ncol=100)
S <- svd(scale(m, center = TRUE, scale=FALSE))
P <- prcomp(m, center = TRUE, scale=FALSE)
plot(S$d, P$sdev) # linearly related
A comparação do modelo nulo é realizada na matriz centralizada abaixo:
library(sinkr) # https://github.com/marchtaylor/sinkr
# centred data
Pnull <- prcompNull(m, center = TRUE, scale=FALSE, nperm = 100)
Pnull$n.sig
boxplot(Pnull$Lambda[,1:20], ylim=range(Pnull$Lambda[,1:20], Pnull$Lambda.orig[1:20]), outline=FALSE, col=8, border="grey50", log="y", main=paste("m (center=FALSE); n sig. =", Pnull$n.sig))
lines(apply(Pnull$Lambda, 2, FUN=quantile, probs=0.95))
points(Pnull$Lambda.orig[1:20], pch=16)
A seguir, é apresentado um gráfico de caixa da matriz permutada com o quantil de 95% de cada valor singular mostrado como a linha sólida. Os valores originais de PCA de m
são os pontos. todos os quais estão abaixo da linha de 95% - Portanto, sua amplitude é indistinguível de ruído aleatório.
O mesmo procedimento pode ser feito na versão não centralizada m
com o mesmo resultado - sem valores singulares significativos:
# centred data
Pnull <- prcompNull(m, center = FALSE, scale=FALSE, nperm = 100)
Pnull$n.sig
boxplot(Pnull$Lambda[,1:20], ylim=range(Pnull$Lambda[,1:20], Pnull$Lambda.orig[1:20]), outline=FALSE, col=8, border="grey50", log="y", main=paste("m (center=TRUE); n sig. =", Pnull$n.sig))
lines(apply(Pnull$Lambda, 2, FUN=quantile, probs=0.95))
points(Pnull$Lambda.orig[1:20], pch=16)
Para comparação, vejamos um conjunto de dados com um conjunto de dados não aleatório: iris
# iris dataset example
m <- iris[,1:4]
Pnull <- prcompNull(m, center = TRUE, scale=FALSE, nperm = 100)
Pnull$n.sig
boxplot(Pnull$Lambda, ylim=range(Pnull$Lambda, Pnull$Lambda.orig), outline=FALSE, col=8, border="grey50", log="y", main=paste("m (center=FALSE); n sig. =", Pnull$n.sig))
lines(apply(Pnull$Lambda, 2, FUN=quantile, probs=0.95))
points(Pnull$Lambda.orig[1:20], pch=16)
Aqui, o 1º valor singular é significativo e explica mais de 92% da variação total:
P <- prcomp(m, center = TRUE)
P$sdev^2 / sum(P$sdev^2)
# [1] 0.924618723 0.053066483 0.017102610 0.005212184