2011-11-28 21 views
14

Estoy usando princomp en R para realizar PCA. Mi matriz de datos es enorme (10K x 10K con cada valor hasta 4 decimales). Toma ~ 3.5 horas y ~ 6.5 GB de memoria física en un procesador Xeon a 2.27 GHz.¿Cuál es la forma más rápida de calcular los dos primeros componentes principales en R?

Como solo quiero los dos primeros componentes, ¿hay una forma más rápida de hacerlo?

Actualización:

Además de la velocidad, ¿Hay una manera eficiente de la memoria para hacer esto?

Se necesitan ~ 2 horas y ~ 6.3 GB de memoria física para calcular los dos primeros componentes usando svd(,2,).

+1

Se puede usar el algoritmo NIPALS. Busque los paquetes R para eso. –

Respuesta

17

A veces tiene acceso a descomposiciones llamadas 'económicas' que le permiten limitar el número de autovalores/eigenvectores. Parece que eigen() y prcomp() no ofrecen esto, pero svd() le permite especificar el número máximo para calcular.

En matrices pequeñas, las ganancias parecen modestos:

R> set.seed(42); N <- 10; M <- matrix(rnorm(N*N), N, N) 
R> library(rbenchmark) 
R> benchmark(eigen(M), svd(M,2,0), prcomp(M), princomp(M), order="relative") 
      test replications elapsed relative user.self sys.self user.child 
2 svd(M, 2, 0)   100 0.021 1.00000  0.02  0   0 
3 prcomp(M)   100 0.043 2.04762  0.04  0   0 
1  eigen(M)   100 0.050 2.38095  0.05  0   0 
4 princomp(M)   100 0.065 3.09524  0.06  0   0 
R> 

pero el factor de tres con respecto a princomp() puede valer la pena reconstruir princomp() de svd() como svd() le permite parar después de dos valores.

+0

Con N = 200 mi máquina hace princomp el más rápido (no por mucho, básicamente igual a svd (, 2), entonces los resultados pueden variar con el procesador y con la escala –

+0

¿Dónde está la función "benchmark"? –

+3

En el paquete rbenchmark También hay un paquete de microbenchmark –

0

Puede escribir la función usted mismo y detenerse en 2 componentes. No es muy difícil. Lo tengo por ahí, si lo encuentro, lo publicaré.

+0

¡Puede ser que pueda dar lógica de función, puedo intentar codificarme! – 384X21

+0

Como introducción a PCA, hice una publicación de blog donde traté de explicar esto en términos de OLS: http: //www.cerebralmastication.com/2010/09/principal-componente-análisis-pca-vs-ordinario-mínimo-cuadrados-o-a-visual-explotación/ abajo en la parte inferior hay un enlace a un artículo de Lindsay I Smith que encontré realmente servicial. Enlace a Smith PDF: http://www.cs.otago.ac.nz/cosc453/student_tutorials/principal_components.pdf –

+0

@JD Long: Es un artículo interesante. Déjame intentarlo ! – 384X21

0

puede utilizar el enfoque de red neuronal para encontrar el componente principal. Descripción básica se da aquí .. http://www.heikohoffmann.de/htmlthesis/node26.html

primer componente principal, y = w1 * x1 + x2 w2 * y componentes ortogonales En segundo lugar se pueden calcular como q = w2 * x1-x2 * W1.

1

El power method podría ser lo que usted desea. Si lo codifica en R, que no es difícil en absoluto, creo que puede encontrar que no es más rápido que el enfoque SVD sugerido en otra respuesta, que hace uso de las rutinas compiladas de LAPACK.

+0

Yo desaconsejaría esto como el método de poder tiene una convergencia extremadamente lenta. –

+0

Esto es cierto en muchos casos. La velocidad depende de la magnitud relativa del autovalor más grande al siguiente, por lo que dependerá del problema. Aún así, creo que el método podría ser competitivo si solo se buscan dos vectores propios y la matriz es muy grande. No hay manera de saberlo sin intentarlo. –

5

El paquete 'svd' proporciona las rutinas para la descomposición SVD/eigen truncada a través del algoritmo Lanczos. Puede usarlo para calcular solo los dos primeros componentes principales.

Aquí me tienen:

> library(svd) 
> set.seed(42); N <- 1000; M <- matrix(rnorm(N*N), N, N) 
> system.time(svd(M, 2, 0)) 
    user system elapsed 
    7.355 0.069 7.501 
> system.time(princomp(M)) 
    user system elapsed 
    5.985 0.055 6.085 
> system.time(prcomp(M)) 
    user system elapsed 
    9.267 0.060 9.368 
> system.time(trlan.svd(M, neig = 2)) 
    user system elapsed 
    0.606 0.004 0.614 
> system.time(trlan.svd(M, neig = 20)) 
    user system elapsed 
    1.894 0.009 1.910 
> system.time(propack.svd(M, neig = 20)) 
    user system elapsed 
    1.072 0.011 1.087 
+0

Como mis datos es una matriz cuadrada, ¿hay un truco para ingresar solo la matriz triangular superior/inferior a cualquiera de las funciones (svd, princomp, prcomp)? ¡Eso ahorraría un gran esfuerzo de memoria al duplicar el triángulo inferior como triángulo superior! – 384X21

+0

No creo que esto sea posible para las funciones "habituales". Para cosas del paquete "svd" puedes usar la llamada "interfaz de matriz externa" donde solo defines cómo multiplicar la matriz por un vector, y eso es todo. En este momento, esta API solo es C-level, pero los rumores dicen que todo se propagará al nivel R normal pronto, de modo que uno puede escribir sus propias rutinas en R (y seguramente explotar la simetría o la dispersión de la matriz). –

4

me trataron aplicación del pcaMethods del paquete del algoritmo NIPALS. Por defecto, calcula los primeros 2 componentes principales. Resulta ser más lento que los otros métodos sugeridos.

set.seed(42); N <- 10; M <- matrix(rnorm(N*N), N, N) 
library(pcaMethods) 
library(rbenchmark) 
m1 <- pca(M, method="nipals", nPcs=2) 
benchmark(pca(M, method="nipals"), 
      eigen(M), svd(M,2,0), prcomp(M), princomp(M), order="relative") 

         test replications elapsed relative user.self sys.self 
3    svd(M, 2, 0)   100 0.02  1.0  0.02  0 
2     eigen(M)   100 0.03  1.5  0.03  0 
4     prcomp(M)   100 0.03  1.5  0.03  0 
5    princomp(M)   100 0.05  2.5  0.05  0 
1 pca(M, method = "nipals")   100 0.23  11.5  0.24  0 
+2

+1 - gracias por hacer comparaciones empíricas. –

Cuestiones relacionadas