2012-02-16 11 views
5

Estoy análisis de grandes conjuntos de datos utilizando el siguiente script:¿Hacer que los bucles anidados sean más eficientes?

M <- c_alignment 
c_check <- function(x){ 
    if (x == c_1) { 
     1 
    }else{ 
     0 
    } 
} 
both_c_check <- function(x){ 
    if (x[res_1] == c_1 && x[res_2] == c_1) { 
     1 
    }else{ 
     0 
    } 
} 
variance_function <- function(x,y){ 
    sqrt(x*(1-x))*sqrt(y*(1-y)) 
} 
frames_total <- nrow(M) 
cols <- ncol(M) 
c_vector <- apply(M, 2, max) 
freq_vector <- matrix(nrow = sum(c_vector)) 
co_freq_matrix <- matrix(nrow = sum(c_vector), ncol = sum(c_vector)) 
insertion <- 0 
res_1_insertion <- 0 
for (res_1 in 1:cols){ 
    for (c_1 in 1:conf_vector[res_1]){ 
     res_1_insertion <- res_1_insertion + 1 
     insertion <- insertion + 1 
     res_1_subset <- sapply(M[,res_1], c_check) 
     freq_vector[insertion] <- sum(res_1_subset)/frames_total 
     res_2_insertion <- 0 
     for (res_2 in 1:cols){ 
      if (is.na(co_freq_matrix[res_1_insertion, res_2_insertion + 1])){ 
       for (c_2 in 1:max(c_vector[res_2])){ 
        res_2_insertion <- res_2_insertion + 1 
        both_res_subset <- apply(M, 1, both_c_check) 
        co_freq_matrix[res_1_insertion, res_2_insertion] <- sum(both_res_subset)/frames_total 
        co_freq_matrix[res_2_insertion, res_1_insertion] <- sum(both_res_subset)/frames_total 
       } 
      } 
     } 
    } 
} 
covariance_matrix <- (co_freq_matrix - crossprod(t(freq_vector))) 
variance_matrix <- matrix(outer(freq_vector, freq_vector, variance_function), ncol = length(freq_vector)) 
correlation_coefficient_matrix <- covariance_matrix/variance_matrix 

Un modelo de entrada sería algo como esto:

1 2 1 4 3 
1 3 4 2 1 
2 3 3 3 1 
1 1 2 1 2 
2 3 4 4 2 

Lo que estoy cálculo de la covarianza es binomial para cada estado encontrado en M[,i] con cada estado encontrado en M[,j]. Cada fila es el estado que se encuentra para esa prueba, y quiero ver cómo varía el estado de las columnas.

Aclaración: Estoy buscando la covarianza de dos distribuciones multinomiales, pero lo hago a través de comparaciones binomiales.

La entrada es una matriz de 4200 x 510, y el valor de c para cada columna es aproximadamente 15 en promedio. Sé que los bucles for son terriblemente lentos en R, pero no estoy seguro de cómo puedo usar la función apply aquí. Si alguien tiene una sugerencia sobre cómo usar correctamente apply aquí, realmente lo agradecería. En este momento, el script tarda varias horas. ¡Gracias!

+0

¿Podría agregar un pequeño conjunto de datos y lo que está tratando de obtener? – aatrujillob

+0

@AndresT Se agregó algo más de información. –

+0

¿Has probado encender el optimizador 'loop que se desenrolla' en el compilador? –

Respuesta

3

No son realmente los bucles anidados de 4 vías, sino la forma en que el código aumenta la memoria en cada iteración. Eso está sucediendo 4 veces donde coloqué # ** en las líneas cbind y rbind. El consejo estándar en R (y Matlab y Python) en situaciones como esta es asignar de antemano y luego completarlo. Eso es lo que hacen las funciones apply. Asignan un list siempre que el número de resultados conocidos, asigne cada resultado a cada ranura, y luego fusionen todos los resultados al final. En su caso, podría asignar la matriz de tamaño correcta por adelantado y asignarla en esos 4 puntos (aproximadamente hablando). Eso debería ser tan rápido como la familia apply, y puede que le resulte más fácil codificar.

15

Pensé en escribir un comentario, pero tengo mucho que decir.

Antes que nada, si crees que la aplicación es más rápida, mira Is R's apply family more than syntactic sugar?. Puede ser, pero está lejos de estar garantizado.

A continuación, no cultive matrices a medida que avance en su código, lo que ralentiza su código increíblemente. preasignar la matriz y llenarla, que puede aumentar la velocidad de su código más de diez veces. Estás creciendo diferentes vectores y matrices a través de su código, que es una locura (perdóname el discurso fuerte)

Entonces, mire la página de ayuda de ?subset y la advertencia dada allí:

Esta es una conveniencia función destinada al uso de forma interactiva. Para la programación es mejor utilizar las funciones de subconjunto estándar como [, y en particular la evaluación no estándar del subconjunto de argumentos puede tener consecuencias imprevistas.

Siempre. Utilizar. Índices.

Además, recalcula los mismos valores una y otra vez. fre_res_2, por ejemplo, se calcula para cada res_2 y state_2 tantas veces como combinaciones de res_1 y state_1. Eso es solo un desperdicio de recursos. Salga de sus bucles lo que no necesita volver a calcular, y guárdelo en matrices a las que puede acceder de nuevo.

Diablos, ahora estoy de acuerdo: por favor, use funciones vectorizadas. Piensa de nuevo y ver lo que puede arrastrar fuera de los bucles: Esto es lo que veo como el núcleo de su cálculo:

cov <- (freq_both - (freq_res_1)*(freq_res_2))/
(sqrt(freq_res_1*(1-freq_res_1))*sqrt(freq_res_2*(1-freq_res_2))) 

mi punto de vista, se puede construir un freq_both matriz, freq_res_1 y freq_res_2 y utilizarlos como entrada para esa línea. Y esa será la matriz de covarianza completa (no lo llame cov, cov es una función). Salir de los bucles Ingrese código rápido.

Teniendo en cuenta el hecho de que no tengo ni idea de lo que hay en c_alignment, no voy a volver a escribir el código para usted, pero definitivamente debe deshacerse de la forma C de pensar y empezar a pensar R.

Que este ser un comienzo: The R Inferno

+1

¡Ojalá pudiera darte +2! gran respuesta y enlaces! – Justin

+0

En particular, observe el Círculo 2 de 'The R Inferno'. –

+0

En segundo lugar el +2 –

Cuestiones relacionadas