Я хочу отфильтровать большую data.table
по группе. Я могу использовать .SD
или .I
, и, хотя я лично считаю, что первое намного легче читать, последнее намного быстрее / использует намного меньше памяти (несмотря на использование .SDcols
).
В некоторой степени мне понятно почему. Для .I
нам нужен вектор для каждой группы, а для .SD
нам нужно целое data.table
. Но я подумал, что, предоставив значимый аргумент .SDcol
, я смог бы ускорить / сохранить некоторую память.
Тем не менее, тесты показывают, что подход .SD
работает примерно в 60 раз медленнее и потребляет в 300 раз больше памяти. , Конечно, 4 столбца .SD
data.table потребуется более чем в 4 раза больше вектора. Но в 60 раз медленнее и в 300 раз больше памяти? Может ли кто-нибудь просветить меня, почему подход .SD
пожирает столько памяти и, следовательно, намного медленнее? Есть ли способ, как я мог ускорить заход на посадку .SD
, чтобы быть быстрее, или это единственный вариант, чтобы вернуться к заходу на посадку .I
?
Настройка данных
library(data.table)
## data set up
nr <- 1e6
nc <- 100
grp_perc <- .8
DT <- data.table(ids = sample(paste0("id",
seq(1, round(grp_perc * nr, 0))),
nr, TRUE))
cols <- paste("col", seq(1, nc), sep = "_")
DT[, (cols) := replicate(nc, sample(nr), simplify = FALSE)]
Тесты
results <- bench::mark(.I = DT[DT[, .(row_id = .I[which.min(col_1)]),
by = ids]$row_id, c("ids", cols[1:3]), with = FALSE],
.SD = DT[, .SD[which.min(col_1)],
by = ids, .SDcols = cols[1:3]],
iterations = 1, filter_gc = FALSE)
summary(results)
# A tibble: 2 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory time gc
<bch:expr> <bch:t> <bch:t> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm> <list> <list> <list> <list>
1 .I 2.64s 2.64s 0.378 34.4MB 0 1 0 2.64s <df[,4] [571,~ <df[,3] [1,41~ <bch:~ <tibble ~
2 .SD 2.73m 2.73m 0.00612 9.1GB 0.342 1 56 2.73m <df[,4] [571,~ <df[,3] [2,40~ <bch:~ <tibble ~