2010-07-26 26 views
28

Supongamos que tiene un marco de datos con muchas filas y muchas columnas.En R, ¿cómo recorre las filas de un marco de datos realmente rápido?

Las columnas tienen nombres. Desea acceder a filas por número y columnas por nombre.

Por ejemplo, una forma (posiblemente lento) a un bucle sobre las filas es

for (i in 1:nrow(df)) { 
    print(df[i, "column1"]) 
    # do more things with the data frame... 
} 

Otra forma es crear "listas" para columnas separadas (como column1_list = df[["column1"]), y acceder a las listas en un bucle. Este enfoque puede ser rápido, pero también inconveniente si desea acceder a muchas columnas.

¿Hay una forma rápida de recorrer las filas de un marco de datos? ¿Hay alguna otra estructura de datos mejor para el bucle rápido?

+1

¿Cómo es esto diferente de df [, "column1"]? ¿También ver? Aplicar con margen = 1. – Greg

+0

El ejemplo no era lo que realmente quería hacer. Quería escribir algunos valores en el marco de datos como datos en un archivo javascript. +1 para la información sobre "margen" en "aplicar". –

+0

Necesitaba recorrer filas para desplazar los valores en columnas en situaciones particulares. Me recordaron que la mejor manera de hacerlo en R es: http://stackoverflow.com/questions/7746567/how-to-swap-values-between-2-columns – thadk

Respuesta

13

Creo que necesito hacer una respuesta completa porque los comentarios me resultan más difíciles de seguir y ya perdí un comentario al respecto ... Hay un ejemplo en nullglob que demuestra las diferencias entre para y aplica funciones familiares mucho mejor que otros ejemplos. Cuando uno hace la función tal que es muy lenta, entonces es donde se consume toda la velocidad y no encontrará diferencias entre las variaciones en el bucle. Pero cuando haces que la función sea trivial, entonces puedes ver cuánto influye el bucle en las cosas.

También me gustaría añadir que algunos miembros de la familia de aplicaciones inexplorados en otros ejemplos tienen propiedades de rendimiento interesantes. Primero mostraré las replicaciones de los resultados relativos de nullglob en mi máquina.

n <- 1e6 
system.time(for(i in 1:n) sinI[i] <- sin(i)) 
    user system elapsed 
5.721 0.028 5.712 

lapply runs much faster for the same result 
system.time(sinI <- lapply(1:n,sin)) 
    user system elapsed 
    1.353 0.012 1.361 

También encontró sapply mucho más lento. Aquí hay algunos otros que no fueron probados.

Llanura de edad se aplican a una versión de la matriz de los datos ...

mat <- matrix(1:n,ncol =1),1,sin) 
system.time(sinI <- apply(mat,1,sin)) 
    user system elapsed 
    8.478 0.116 8.531 

Por lo tanto, el comando de aplicación() en sí es sustancialmente más lento que el bucle. (Para bucle no se ralentiza apreciablemente si uso pecado (mat [i, 1]).

Otro que no parece ser probado en otros puestos es tapply.

system.time(sinI <- tapply(1:n, 1:n, sin)) 
    user system elapsed 
12.908 0.266 13.589 

Por supuesto , uno nunca usaría tapply de esta manera y su utilidad está más allá de cualquier problema de velocidad en la mayoría de los casos.

+1

+1 para la referencia a nullglob. Su publicación tiene una referencia al artículo "¿Cómo puedo evitar este bucle o hacerlo más rápido?", De Uwe Ligges y John Fox, en "R News", mayo de 2008. Gracias por escribir sobre las funciones de aplicación. –

11

La manera más rápida es no loop (es decir, operaciones vectorizadas). Una de las únicas instancias en las que debe realizar un bucle es cuando hay dependencias (es decir, una iteración depende de otra). De lo contrario, intente hacer la mayor cantidad de cálculos vectorizados fuera del bucle como sea posible.

Si haces necesidad de bucle, a continuación, utilizando un bucle for es esencialmente más rápido que cualquier otra cosa (lapply puede ser un poco más rápido, pero other apply functions tend to be around the same speed as for).

+1

Quizás no haya forma de evitar el ciclo de lo que quería hacer --- ver mi respuesta al comentario de Greg anterior. –

+1

"alrededor de la misma velocidad"? ¿Has leído todas las respuestas? En mi respuesta, muestro que usar vapply es 3 veces más rápido (para ese ejemplo) que el bucle for ... – Tommy

+2

En términos de eficiencia algorítmica, son muy similares en velocidad: [eficiencia algorítmica] (http: // es .wikipedia.org/wiki/Algorithmic_efficiency) – Toby

0

Explotando el hecho de que data.frames son esencialmente listas de vectores de columna, se puede usar do.call para aplicar una función con la ariad del número de columnas sobre cada columna del data.frame (similar a un "zip" sobre una lista en otros idiomas).

do.call(paste, data.frame(x=c(1,2), z=c("a","b"), z=c(5,6))) 
+0

Pero eso no es bucle. –

Cuestiones relacionadas