R Почему dplyr считает уникальные значения (n_distinct) по группам быстрее, чем data.table (uniqueN)? - PullRequest
2 голосов
/ 10 марта 2020

Как я понимаю, data.table более эффективен и быстрее, чем dplyr, но сегодня я обнаружил противоположную ситуацию в своей работе. Я создал симуляцию, чтобы объяснить ситуацию.

library(data.table)
library(dplyr)

library(microbenchmark)

#  data simulated
dt = data.table(A = sample(1:4247,10000, replace = T),
                B = sample(1:119,10000,replace = T),
                C = sample(1:6,10000,replace = T),
                D = sample(1:30,10000,replace = T))

dt[,ID:=paste(A, ":::" , 
              D,":::",
              C)]
# execution time

microbenchmark(
  DATA_TABLE = dt[, .(count=uniqueN(ID)), 
                  by=c("A","B","C")
                  ],
  DPLYR      = dt %>% 
               group_by(A,B,C)  %>% 
               summarise(count = n_distinct(ID)),
  times = 10
              )

Результаты

Unit: milliseconds
       expr         min          lq        mean      median    uq         max        neval
 DATA_TABLE 14241.57361 14305.67026 15585.80472 14651.16402  16244.22477 21367.56866  10
      DPLYR    35.95123    37.63894    47.62637    48.56598  53.59919    62.63978     10 

Вы видите большую разницу! Кто-то знает причину? Есть ли у вас какие-либо советы о том, когда использовать dplyr или data.table?

У меня есть полный код в синтаксисе data.table, теперь я не знаю, нужно ли мне переводить некоторые куски кода в dplyr из-за этой ситуации.

Заранее спасибо.

1 Ответ

1 голос
/ 11 марта 2020

Вот еще один вариант:

dt[order(A, B, C), {
        uniqn <- rleidv(c(.SD, .(ID)))
        lastidx <- c(which(diff(rowidv(.SD))<1L), .N)
        c(.SD[lastidx], .(count=c(uniqn[lastidx[1L]], diff(uniqn[lastidx]))))
    }, .SDcols=cols]

временной код:

cols <- c("A","B","C")
microbenchmark(times=1L,
    DATA_TABLE = a00 <- dt[, .(count=uniqueN(ID)), cols],
    DATA_TABLE1 = a01 <- dt[, .(count=length(unique(ID))), cols],
    DPLYR      = a1 <- dt %>%
        group_by(A,B,C)  %>%
        summarise(count = n_distinct(ID)),
    mtd2       = a2 <- dt[order(A, B, C), {
        uniqn <- rleidv(c(.SD, .(ID)))
        lastidx <- c(which(diff(rowidv(.SD))<1L), .N)
        c(.SD[lastidx], .(count=c(uniqn[lastidx[1L]], diff(uniqn[lastidx]))))
    }, .SDcols=cols]
)

fsetequal(a00, a01))
#[1] TRUE

fsetequal(a01, setDT(a1))
#[1] TRUE

fsetequal(setDT(a1), a2)
#[1] TRUE

время:

Unit: milliseconds
        expr         min          lq        mean      median          uq         max neval
  DATA_TABLE 459346.4602 459346.4602 459346.4602 459346.4602 459346.4602 459346.4602     1
 DATA_TABLE1   6404.5130   6404.5130   6404.5130   6404.5130   6404.5130   6404.5130     1
       DPLYR   3988.2554   3988.2554   3988.2554   3988.2554   3988.2554   3988.2554     1
        mtd2    156.3265    156.3265    156.3265    156.3265    156.3265    156.3265     1

данные с 1 миллионами строк:

library(data.table)
library(dplyr)
library(microbenchmark)

#  data simulated
set.seed(0L)
nr <- 1e6
dt = data.table(A = sample(1:424700,nr, replace = T),
    B = sample(1:11900,nr, replace = T),
    C = sample(1:600, nr, replace = T),
    D = sample(1:3000, nr, replace = T))
dt[,ID:=paste(A,":::",D,":::",C)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...