Por ejemplo (aunque no estoy seguro si es el ejemplo más representativo):
N <- 1e6
d1 <- data.frame(x=sample(N,N), y1=rnorm(N))
d2 <- data.frame(x=sample(N,N), y2=rnorm(N))
Esto es lo que tengo hasta ahora:
d <- merge(d1,d2)
# 7.6 sec
library(plyr)
d <- join(d1,d2)
# 2.9 sec
library(data.table)
dt1 <- data.table(d1, key="x")
dt2 <- data.table(d2, key="x")
d <- data.frame( dt1[dt2,list(x,y1,y2=dt2$y2)] )
# 4.9 sec
library(sqldf)
sqldf()
sqldf("create index ix1 on d1(x)")
sqldf("create index ix2 on d2(x)")
d <- sqldf("select * from d1 inner join d2 on d1.x=d2.x")
sqldf()
# 17.4 sec
performance
r
join
merge
data.table
datasmurf
fuente
fuente
Respuestas:
El enfoque de coincidencia funciona cuando hay una clave única en el segundo marco de datos para cada valor de clave en el primero. Si hay duplicados en el segundo marco de datos, los enfoques de combinación y fusión no son los mismos. El partido es, por supuesto, más rápido ya que no hace tanto. En particular, nunca busca claves duplicadas. (continúa después del código)
En el código sqldf que se publicó en la pregunta, podría parecer que se usaron índices en las dos tablas pero, de hecho, se colocan en tablas que se sobrescribieron antes de que se ejecutara la selección SQL y eso, en parte, explica por qué es tan lento. La idea de sqldf es que los marcos de datos en su sesión de R constituyen la base de datos, no las tablas en sqlite. Por lo tanto, cada vez que el código se refiere a un nombre de tabla no calificado, lo buscará en su espacio de trabajo de R, no en la base de datos principal de sqlite. Por lo tanto, la declaración de selección que se mostró lee d1 y d2 desde el espacio de trabajo en la base de datos principal de sqlite, superando las que estaban allí con los índices. Como resultado, realiza una combinación sin índices. Si quisiera hacer uso de las versiones de d1 y d2 que estaban en la base de datos principal de sqlite, tendría que referirse a ellas como main.d1 y main. d2 y no como d1 y d2. Además, si está intentando que se ejecute lo más rápido posible, tenga en cuenta que una combinación simple no puede hacer uso de índices en ambas tablas, por lo que puede ahorrar el tiempo de crear uno de los índices. En el código siguiente ilustramos estos puntos.
Vale la pena notar que el cálculo preciso puede marcar una gran diferencia sobre qué paquete es más rápido. Por ejemplo, hacemos una combinación y un agregado a continuación. Vemos que los resultados casi se invierten para los dos. En el primer ejemplo, de más rápido a más lento, obtenemos: data.table, plyr, merge y sqldf, mientras que en el segundo ejemplo sqldf, aggregate, data.table y plyr, casi al revés del primero. En el primer ejemplo, sqldf es 3 veces más lento que data.table y en el segundo es 200 veces más rápido que plyr y 100 veces más rápido que data.table. A continuación, mostramos el código de entrada, los tiempos de salida para la fusión y los tiempos de salida para el agregado. También vale la pena señalar que sqldf se basa en una base de datos y, por lo tanto, puede manejar objetos más grandes de lo que R puede manejar (si usa el argumento dbname de sqldf) mientras que los otros enfoques se limitan al procesamiento en la memoria principal. También hemos ilustrado sqldf con sqlite pero también es compatible con las bases de datos H2 y PostgreSQL.
Los resultados de las dos llamadas de referencia comparando los cálculos de fusión son:
El resultado de la llamada de referencia que compara los cálculos agregados es:
fuente
Los 132 segundos informados en los resultados de Gabor
data.table
son en realidad funciones de base de tiempocolMeans
ycbind
(la asignación de memoria y la copia inducida por el uso de esas funciones). También hay buenas y malas formas de consumirdata.table
.Tenga en cuenta que no conozco bien a plyr, así que consulte con Hadley antes de confiar en los
plyr
horarios aquí. También tenga en cuenta quedata.table
incluyen el tiempo para convertirdata.table
y establecer la clave, para la tarifa.Esta respuesta se ha actualizado desde que se respondió originalmente en diciembre de 2010. A continuación se muestran los resultados de referencia anteriores. Consulte el historial de revisión de esta respuesta para ver qué cambió.
fuente
.Internal
llamadas en paquetes CRAN, consulte la Política de repositorio de CRAN .data.table
se optimiza automáticamentemean
ahora (sin llamar.Internal
internamente).for
ciclo, eso es bueno. ¿Podría agregar más información sobre el "análisis SEM" a ese problema? Por ejemplo, supongo que SEM = ¿microscopio electrónico de barrido? Saber más sobre la aplicación nos hace más interesante y nos ayuda a priorizar.Para una tarea simple (valores únicos en ambos lados de la combinación) utilizo
match
:Es mucho más rápido que fusionar (en mi máquina 0.13s a 3.37s).
Mis tiempos:
merge
: 3,32 splyr
: 0,84 smatch
: 0,12 sfuente
Pensé que sería interesante publicar un punto de referencia con dplyr en la mezcla: (tenía muchas cosas ejecutándose)
Recien agregado:
y configure los datos para dplyr con una tabla de datos:
Actualizado: eliminé data.tableBad y plyr y nada más que RStudio open (i7, 16GB de ram).
Con data.table 1.9 y dplyr con marco de datos:
Con data.table 1.9 y dplyr con tabla de datos:
Por coherencia, aquí está el original con all y data.table 1.9 y dplyr usando una tabla de datos:
Creo que estos datos son demasiado pequeños para los nuevos datos.table y dplyr :)
Conjunto de datos más grande:
Tomó alrededor de 10-13 GB de RAM solo para almacenar los datos antes de ejecutar el punto de referencia.
Resultados:
Probé un mil millones pero estalló el ariete. 32GB lo manejarán sin problemas.
[Editar por Arun] (dotcomken, ¿podría ejecutar este código y pegar los resultados de su evaluación comparativa? Gracias).
Según la solicitud de Arun aquí, el resultado de lo que me proporcionó para ejecutar:
Perdón por la confusión, la noche me afectó.
Usar dplyr con marco de datos parece ser la forma menos eficiente de procesar resúmenes. ¿Se incluyen estos métodos para comparar la funcionalidad exacta de data.table y dplyr con sus métodos de estructura de datos? Casi preferiría separar eso, ya que la mayoría de los datos deberán limpiarse antes de agrupar_por o crear la tabla de datos. Podría ser una cuestión de gustos, pero creo que la parte más importante es la eficacia con la que se pueden modelar los datos.
fuente
Utilizando la función de combinación y sus parámetros opcionales:
Inner join: merge (df1, df2) funcionará para estos ejemplos porque R une automáticamente los marcos mediante nombres de variables comunes, pero lo más probable es que desee especificar merge (df1, df2, by = "CustomerId") para asegurarse de que coincidían solo en los campos que deseaba. También puede usar los parámetros by.xy by.y si las variables coincidentes tienen nombres diferentes en los diferentes marcos de datos.
fuente