Mi sono abituato a ottenere i miei dati con il dplyr, ma alcuni dei calcoli sono "lenti". In particolare sottoinsieme per gruppi, ho letto che dplyr è lento quando c'è un sacco di gruppi e basato su this benchmark data.table potrebbe essere più veloce quindi ho iniziato a imparare data.table.Come velocizzare il sottogruppo per gruppi
Ecco come riprodurre qualcosa vicino ai miei dati reali con 250k righe e circa 230k gruppi. Vorrei raggruppare per id1, id2 e impostare le righe con lo max(datetime)
per ogni gruppo.
Dati
# 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"))
non riuscivo a trovare la retta via per sottoinsieme da gruppi con data.table così ho fatto questa domanda: Filter rows by groups with data.table
Consigliamo me di utilizzare .SD:
datas.dt[, .SD[datetime == max(datetime)], by = c("id1", "id2")]
Ma ho due problemi, funziona con la data ma non con POSIXct ("Errore in UseMethod (" as.data.table "): nessun metodo applicabile per 'as.data. tabella 'applicata a un oggetto di classe "c (' POSIXct ',' POSIXt ')" "), e questo è molto lento. Ad esempio, con le date:
> 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
così ho trovato altro modo molto più veloce per raggiungere questo obiettivo (e mantenendo datetimes) con data.table:
Funzioni
f.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]
ma poi ho pensato di dati. tabella sarebbe molto più veloce, la differenza di tempo con dplyr non è significativa.
microbenchmark
mbm <- 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
mi sto perdendo/abuso qualcosa con data.table? Hai idee per accelerare questo calcolo?
Qualsiasi aiuto sarebbe molto apprezzato! Grazie
Modifica: alcune precisioni relative alle versioni di sistema e pacchetti utilizzate per il microbenchmark. (Il computer non è una macchina da guerra, 12Go i5)
sistema
sessionInfo()
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’
Si desidera ottenere tutti i valori uguali a max o solo il primo valore come 'which.max' restituisce? Anche 'datas.dt [, .SD [as.Date (datetime) == max (as.Date (datetime))], per = c (" id1 "," id2 ")]' è una cattiva pratica. Devi convertire 'date' in' IDate' class prima del subsetting. –
Solo per divertimento, puoi aggiungere 'x%>% group_by (id1, id2)%>% slice (che (datetime == max (datetime)))' al tuo confronto? –
Anche 'datas.dt [, datetime: = as.IDate (datetime)]; system.time (datas.dt [datas.dt [, .I [datetime == max (datetime)], di = c ("id1", "id2")] $ V1]) 'funziona solo 5 secondi rispetto a 200 quando usi '.SD', quindi trovo difficile credere ai tuoi benchmark. –