Я использовал для достижения своих данных перебор с dplyr, но некоторые из вычислений являются «медленными». В частности, подмножество по группам, я читал, что dplyr медленный, когда есть много групп, и на основе данных this benchmark.table может быть быстрее, поэтому я начал изучать data.table.Как ускорить подмножество по группам
Вот как воспроизвести что-то близкое к моим реальным данным с 250 тыс. Строк и около 230 тыс. Групп. Я хотел бы сгруппировать по id1, id2 и подмножество строк с max(datetime)
для каждой группы.
Datas
# 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"))
Я не мог найти прямой путь к подмножеству групп с data.table поэтому я задал этот вопрос: Filter rows by groups with data.table
Мы предлагаем мне использовать .sd:
datas.dt[, .SD[datetime == max(datetime)], by = c("id1", "id2")]
Но у меня есть две проблемы: он работает с датой, но не с POSIXct («Ошибка в UseMethod (« as.data.table »): нет применимого метода для 'as.data. table "применяется к объекту класса" c ('POSIXct', 'POSIXt') ""), и это очень медленно. Например, с датами:
> 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
Так что я нашел другой путь гораздо быстрее, чтобы достичь этого (и сохраняя DateTimes) с data.table:
Функции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]
Но тогда я думал, что данные. таблица будет намного быстрее, разница во времени с dplyr не является значимой.
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
Я пропускаю/злоупотребляя что-то с data.table? У вас есть идеи ускорить это вычисление?
Любая помощь была бы высоко оценена! Спасибо
Редактировать: Некоторые сведения о версиях системы и пакетов, используемых для микрообъектива. (Компьютер не боевая машина, 12Go i5)
Система
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’
Вы хотите получить все значения, равные max или только первое значение, например 'which.max'? Также 'datas.dt [, .SD [as.Date (datetime) == max (as.Date (datetime))], by = c (" id1 "," id2 ")]' является плохой практикой. Вы должны преобразовать 'date' в класс' IDate' перед подмножеством. –
Просто для удовольствия вы можете добавить 'x%>% group_by (id1, id2)%>% slice (который (datetime == max (datetime)))' к вашему сравнению? –
Также 'datas.dt [, datetime: = as.IDate (datetime)]; system.time (datas.dt [datas.dt [, .I [datetime == max (datetime)], by = c ("id1", "id2")] $ V1]) 'работает всего 5 секунд по сравнению с 200 при использовании '.SD', поэтому мне трудно поверить в ваши тесты. –