2012-05-06 10 views
14

Sé que no es la mejor práctica en R utilizar el bucle for porque no tiene un rendimiento mejorado. Para casi todos los casos, existe una función de la familia *apply que resuelve nuestros problemas.Loops in R - ¿Necesita utilizar el índice, de todos modos para evitar 'para'?

Sin embargo, estoy frente a una situación en la que no veo una solución alternativa.

necesito para calcular la variación ciento para valores consecutivos:

pv[1] <- 0 
for(i in 2:length(x)) { 
    pv[i] <- (x[i] - x[i-1])/x[i-1] 
} 

Por lo tanto, como se puede ver, tengo que usar tanto el elemento x[i], sino también el elemento x[i-1]. Al usar las funciones *apply, solo veo cómo usar el x[i]. ¿Hay alguna manera de evitar los for bucles?

Respuesta

18

Lo que ofrecen sería la variación fraccional, pero si se multiplica por 100 se obtiene el "porcentaje de variación":

pv<- vector("numeric",length(x)) 
pv[1] <- 0 
pv[-1] <- 100* (x[-1] - x[-length(x)])/ x[-length(x)] 

solución vectorizada. (Y debe tener en cuenta que los bucles foráneos van a ser tan lentos como * aplicar soluciones ... simplemente no tan bonitos. Siempre busque un enfoque vectorizado.)

Para explicar un poco más: El x[-length(x)] es el vector, x[1:(length{x-1)], y x[-1] es el vector, x[2:length(x)], y las operaciones vectoriales en R están haciendo las mismas operaciones que en su cuerpo for-loop, aunque no usan un bucle explícito. R primero construye las diferencias en esos vectores desplazados, , y luego se divide por x[1:(length{x-1)].

+0

Buena respuesta DWin. No sabía realmente qué estaba logrando el cartel, pero estoy 100% de acuerdo con la vectorización.+1 –

+0

Muy buena respuesta! No sabía que el enfoque vectorizado era el más rápido, pensé que 'lapply' era. Pero en la última línea de código, ¿no debería ser 'x [-1] - x [-length (x)]'? –

+0

@ JoãoDaniel: Sí, debería. Editar aplicado –

20

Usted puede obtener los mismos resultados con:

pv <- c(0) 
y <- sapply(2:length(x), function(i) {pv <<- (x[i] - x[i-1])/x[i-1]}) 
c(0, y) 

El bucle de cuestiones que una vez fueron un problema han sido optimizados. A menudo, un bucle for no es más lento e incluso puede ser más rápido que la solución aplicada. Tienes que probarlos a los dos y ver. Apuesto a que tu bucle for es más rápido que mi solución.

EDIT: Para ilustrar la solución for loop versus apply así como lo que DWin discute sobre la vectorización ejecuté la evaluación comparativa de las cuatro soluciones usando microbenchmark en una máquina win 7.

Unit: microseconds 
      expr  min  lq median  uq  max 
1 DIFF_Vincent 22.396 25.195 27.061 29.860 2073.848 
2  FOR.LOOP 132.037 137.168 139.968 144.634 56696.989 
3   SAPPLY 146.033 152.099 155.365 162.363 2321.590 
4 VECTORIZED_Dwin 18.196 20.063 21.463 23.328 536.075 

enter image description here

+0

Cuál es la versión "DIF" y lo que la mirada del conjunto prueba? La solución de @VincentZoonekynd es la más rápida para mí. – Tommy

+0

Debería haber sido DIFF para diff (Vincent's). Para ser justos con la evaluación comparativa, no se olvide de sacar el * 100 de la solución de DWin, ya que esto agrega un cálculo adicional que es un porcentaje (no una proporción como la solución de todos los EE. UU.). –

+0

+1 por la belleza del gráfico! –

16

También puede utilizar diff:

c(0, diff(x)/x[-length(x)]) 
c(0, exp(diff(log(x))) - 1) 
+0

+1 Este parece ser el más rápido ... Y me gusta la variante de registro/exp aunque no es tan rápido. – Tommy

+0

Punta de sombrero: Tengo que admitir que el enfoque de diff() es algo más elegante que mi traducción literal a una solución vectorizada. Me sorprendió que no marcara mejor. –

+0

@DWin - cuando benchmark, usar 'diff' o no hace ninguna diferencia. Pero usar 'c' en lugar de tu reemplazo es mucho más rápido. Algo es sospechoso sobre los números de Tyler. Lo ejecuté en 'x <- runif (1e7)' ... – Tommy

Cuestiones relacionadas