Cómo acelerar el subconjunto por grupos
Solía lograr que mis datos se disputaran con dplyr, pero algunos de los cálculos son "lentos". En particular, subgrupo por grupos, leí que dplyr es lento cuando hay muchos grupos y basado eneste punto de referencia data.table podría ser más rápido, así que comencé a aprender data.table.
Aquí es cómo reproducir algo cercano a mis datos reales con 250k filas y aproximadamente 230k grupos. Me gustaría agrupar por id1, id2 y subconjunto de las filas con elmax(datetime)
para cada grupo
# random datetime generation function by Dirk Eddelbuettel
# https://stackoverflow.com/questions/14720983/efficiently-generate-a-random-sample-of-times-and-dates-between-two-dates
rand.datetime <- function(N, st = "2012/01/01", et = "2015/08/05") {
st <- as.POSIXct(as.Date(st))
et <- as.POSIXct(as.Date(et))
dt <- as.numeric(difftime(et,st,unit="sec"))
ev <- sort(runif(N, 0, dt))
rt <- st + ev
}
set.seed(42)
# Creating 230000 ids couples
ids <- data.frame(id1 = stringi::stri_rand_strings(23e4, 9, pattern = "[0-9]"),
id2 = stringi::stri_rand_strings(23e4, 9, pattern = "[0-9]"))
# Repeating randomly the ids[1:2000, ] to create groups
ids <- rbind(ids, ids[sample(1:2000, 20000, replace = TRUE), ])
# Adding random datetime variable and dummy variables to reproduce real datas
datas <- transform(ids,
datetime = rand.datetime(25e4),
var1 = sample(LETTERS[1:6], 25e4, rep = TRUE),
var2 = sample(c(1:10, NA), 25e4, rep = TRUE),
var3 = sample(c(1:10, NA), 25e4, rep = TRUE),
var4 = rand.datetime(25e4),
var5 = rand.datetime(25e4))
datas.tbl <- tbl_df(datas)
datas.dt <- data.table(datas, key = c("id1", "id2"))
No pude encontrar la forma directa de subgrupo por grupos con data.table, así que hice esta pregunta:Filtrar filas por grupos con data.table
Sugerimos que use .SD:
datas.dt[, .SD[datetime == max(datetime)], by = c("id1", "id2")]
Pero tengo dos problemas, funciona con fecha pero no con POSIXct ("Error en UseMethod (" as.data.table "): ningún método aplicable para 'as.data.table' aplicado a un objeto de la clase" c (' POSIXct ',' POSIXt ') ""), y esto es muy lento. Por ejemplo con fechas:
> system.time({
+ datas.dt[, .SD[as.Date(datetime) == max(as.Date(datetime))], by = c("id1", "id2")]
+ })
utilisateur système écoulé
207.03 0.00 207.48
Así que encontré otra forma mucho más rápida de lograr esto (y mantener las fechas y horas) con data.table:
Las funcionesf.dplyr <- function(x) x %>% group_by(id1, id2) %>% filter(datetime == max(datetime))
f.dt.i <- function(x) x[x[, .I[datetime == max(datetime)], by = c("id1", "id2")]$V1]
f.dt <- function(x) x[x[, datetime == max(datetime), by = c("id1", "id2")]$V1]
Pero luego pensé que data.table sería mucho más rápido, la diferencia horaria con dplyr no es significativa.
Microbenchmarkmbm <- microbenchmark(
dplyr = res1 <- f.dplyr(datas.tbl),
data.table.I = res2 <- f.dt.i(datas.dt),
data.table = res3 <- f.dt(datas.dt),
times = 50L)
Unit: seconds
expr min lq mean median uq max neval
dplyr 31.84249 32.24055 32.59046 32.61311 32.88703 33.54226 50
data.table.I 30.02831 30.94621 31.19660 31.17820 31.42888 32.16521 50
data.table 30.28923 30.84212 31.09749 31.04851 31.40432 31.96351 50
¿Me falta / uso incorrecto de algo con data.table? ¿Tienes ideas para acelerar este cálculo?
Cualquier ayuda sería muy apreciada ! Gracias
Editar: Algunas precisiones sobre el sistema y las versiones de paquetes utilizados para el microbenchmark. (La computadora no es una máquina de guerra, 12Go i5)
SistemasessionInfo()
R version 3.1.3 (2015-03-09)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1
locale:
[1] LC_COLLATE=French_France.1252 LC_CTYPE=French_France.1252
[3] LC_MONETARY=French_France.1252 LC_NUMERIC=C
[5] LC_TIME=French_France.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] readr_0.1.0 ggplot2_1.0.1 microbenchmark_1.4-2
[4] data.table_1.9.4 dplyr_0.4.1 plyr_1.8.2
loaded via a namespace (and not attached):
[1] assertthat_0.1 chron_2.3-45 colorspace_1.2-6 DBI_0.3.1
[5] digest_0.6.8 grid_3.1.3 gtable_0.1.2 lazyeval_0.1.10
[9] magrittr_1.5 MASS_7.3-39 munsell_0.4.2 parallel_3.1.3
[13] proto_0.3-10 Rcpp_0.11.5 reshape2_1.4.1 scales_0.2.4
[17] stringi_0.4-1 stringr_0.6.2 tools_3.1.3
> packageVersion("data.table")
[1] ‘1.9.4’
> packageVersion("dplyr")
[1] ‘0.4.1’