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)
DF1 = data.frame(a = c(1, 1, 2, 2), b = 1:4)
DF2 = data.frame(b = c(1, 2, 3, 3, 4), c = letters[1:5])
merge(DF1, DF2)
b a c
1 1 1 a
2 2 1 b
3 3 2 c
4 3 2 d
5 4 2 e
DF1$c = DF2$c[match(DF1$b, DF2$b)]
DF1$c
[1] a b c e
Levels: a b c d e
> DF1
a b c
1 1 1 a
2 1 2 b
3 2 3 c
4 2 4 e
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.
library(plyr)
library(data.table)
library(sqldf)
set.seed(123)
N <- 1e5
d1 <- data.frame(x=sample(N,N), y1=rnorm(N))
d2 <- data.frame(x=sample(N,N), y2=rnorm(N))
g1 <- sample(1:1000, N, replace = TRUE)
g2<- sample(1:1000, N, replace = TRUE)
d <- data.frame(d1, g1, g2)
library(rbenchmark)
benchmark(replications = 1, order = "elapsed",
merge = merge(d1, d2),
plyr = join(d1, d2),
data.table = {
dt1 <- data.table(d1, key = "x")
dt2 <- data.table(d2, key = "x")
data.frame( dt1[dt2,list(x,y1,y2=dt2$y2)] )
},
sqldf = sqldf(c("create index ix1 on d1(x)",
"select * from main.d1 join d2 using(x)"))
)
set.seed(123)
N <- 1e5
g1 <- sample(1:1000, N, replace = TRUE)
g2<- sample(1:1000, N, replace = TRUE)
d <- data.frame(x=sample(N,N), y=rnorm(N), g1, g2)
benchmark(replications = 1, order = "elapsed",
aggregate = aggregate(d[c("x", "y")], d[c("g1", "g2")], mean),
data.table = {
dt <- data.table(d, key = "g1,g2")
dt[, colMeans(cbind(x, y)), by = "g1,g2"]
},
plyr = ddply(d, .(g1, g2), summarise, avx = mean(x), avy=mean(y)),
sqldf = sqldf(c("create index ix on d(g1, g2)",
"select g1, g2, avg(x), avg(y) from main.d group by g1, g2"))
)
Los resultados de las dos llamadas de referencia comparando los cálculos de fusión son:
Joining by: x
test replications elapsed relative user.self sys.self user.child sys.child
3 data.table 1 0.34 1.000000 0.31 0.01 NA NA
2 plyr 1 0.44 1.294118 0.39 0.02 NA NA
1 merge 1 1.17 3.441176 1.10 0.04 NA NA
4 sqldf 1 3.34 9.823529 3.24 0.04 NA NA
El resultado de la llamada de referencia que compara los cálculos agregados es:
test replications elapsed relative user.self sys.self user.child sys.child
4 sqldf 1 2.81 1.000000 2.73 0.02 NA NA
1 aggregate 1 14.89 5.298932 14.89 0.00 NA NA
2 data.table 1 132.46 47.138790 131.70 0.08 NA NA
3 plyr 1 212.69 75.690391 211.57 0.56 NA NA