2010-06-28 29 views
5

Buenos días,Loops ineficiencia en I

he estado desarrollando desde hace unos meses en R y que tiene que asegurarse de que el tiempo de ejecución de mi código no es demasiado largo, porque analizo grandes conjuntos de datos.

Por lo tanto, he estado tratando de usar tantas funciones vectorizadas como sea posible.

Sin embargo, todavía me estoy preguntando algo.

Lo que es costoso en R no es el ciclo en sí ¿no? Es decir, el problema surge cuando comienzas a modificar variables dentro del ciclo, por ejemplo ¿es correcto?

Por lo tanto, estaba pensando, ¿qué pasa si simplemente tiene que ejecutar una función en cada elemento (en realidad no le importa el resultado). Por ejemplo, para escribir datos en una base de datos. ¿Qué deberías hacer?

1) ¿Utiliza mapply sin almacenar el resultado en ninguna parte?

2) hacemos un ciclo sobre el vector y solo aplicamos f (i) a cada elemento?

3) ¿Hay alguna función mejor que podría haber pasado por alto?

(eso por supuesto suponiendo que su función no está óptimamente vectorizada).

¿Qué pasa con el paquete foreach? ¿Has experimentado alguna mejora en el rendimiento al usarlo?

+1

Voy a dejar la respuesta a alguien que es más experto que yo, pero en mi experiencia práctica los * Se aplican las funciones normalmente (pero no siempre) acelerar la cosa un poco. – nico

+0

Supongo que sí, porque el ciclo está hecho "en C" y no directamente a través de R. – SRKX

+1

Consulte esta publicación SO en la familia de aplicaciones - http: // stackoverflow.com/questions/2275896/is-rs-apply-family-more-than-syntactic-sugar – csgillespie

Respuesta

6

Solo un par de comentarios. Un bucle for es más o menos tan rápido como apply y sus variantes, y las aceleraciones reales vienen cuando vectoriza su función tanto como sea posible (es decir, utilizando bucles de bajo nivel, en lugar de apply, que solo oculta el bucle for) . No estoy seguro de si este es el mejor ejemplo, pero considere lo siguiente:

> n <- 1e06 
> sinI <- rep(NA,n) 
> system.time(for(i in 1:n) sinI[i] <- sin(i)) 
    user system elapsed 
    3.316 0.000 3.358 
> system.time(sinI <- sapply(1:n,sin)) 
    user system elapsed 
    5.217 0.016 5.311 
> system.time(sinI <- unlist(lapply(1:n,sin), 
+  recursive = FALSE, use.names = FALSE)) 
    user system elapsed 
    1.284 0.012 1.303 
> system.time(sinI <- sin(1:n)) 
    user system elapsed 
    0.056 0.000 0.057 

En uno de los comentarios a continuación, Marek señala que el tiempo parte del bucle for anterior es en realidad la parte ]<-:

> system.time(sinI <- unlist(lapply(1:n,sin), 
+  recursive = FALSE, use.names = FALSE)) 
    user system elapsed 
    1.284 0.012 1.303 

los cuellos de botella que no puede ser inmediatamente vectorizado puede ser reescrita en C o Fortran, compilan con R CMD SHLIB, y luego enchufados con .Call, .C o .Fortran.

También, vea theselinks para más información sobre la optimización de bucle en R. Consulte también el artículo "How Can I Avoid This Loop or Make It Faster?" en R News.

+0

no es la función de aplicación que maneja mejor el bucle desde su implementación en C? La pregunta es de hecho general, ¿es mejor usar Reducir que la implementación de un bucle simple (por ejemplo) en su opinión? – SRKX

+3

En la versión 'sapply', la mayor parte del tiempo se gasta en resultados de posprocesamiento. Cuando hagas 'system.time (sinI <- unlist (lapply (1: n, sin), FALSE, FALSE))' deberías obtener la versión más rápida (no de 'sin (1: n)' por supuesto). En 'for' loop que consume mucho tiempo es' [<-', comprueba 'system.time (para (i en 1: n) sin (i))' (en este caso es inútil causa drop results). – Marek

4

vapply evita el postprocesamiento al requerir que especifique cuál es el valor de retorno. Resulta ser 3,4 veces más rápido que el bucle for:

> system.time(for(i in 1:n) sinI[i] <- sin(i)) 
    user system elapsed 
    2.41 0.00 2.39 

> system.time(sinI <- unlist(lapply(1:n,sin), recursive = FALSE, use.names = FALSE)) 
    user system elapsed 
    1.46 0.00 1.45 

> system.time(sinI <- vapply(1:n,sin, numeric(1))) 
    user system elapsed 
    0.71 0.00 0.69