我正在使用具有多个组(+ 2mil)的模拟数据集,在这里我想为每个组计算观察的总数和超过阈值(此处为2)的观察数。

当我创建一个标志变量时,它看起来要快得多,尤其是对于dplyr而言,对于data.table而言则要快一些。

为什么会这样?在每种情况下,它在后台如何工作?

在下面查看我的示例。

模拟数据集

# create an example dataset
set.seed(318)

N = 3000000 # number of rows

dt = data.frame(id = sample(1:5000000, N, replace = T),
                value = runif(N, 0, 10))

使用dplyr
library(dplyr)

# calculate summary variables for each group
t = proc.time()
dt2 = dt %>% group_by(id) %>% summarise(N = n(),
                                        N2 = sum(value > 2))
proc.time() - t

# user  system elapsed
# 51.70    0.06   52.11


# calculate summary variables for each group after creating a flag variable
t = proc.time()
dt2 = dt %>% mutate(flag = ifelse(value > 2, 1, 0)) %>%
  group_by(id) %>% summarise(N = n(),
                             N2 = sum(flag))
proc.time() - t

# user  system elapsed
# 3.40    0.16    3.55

使用data.table
library(data.table)

# set as data table
dt2 = setDT(dt, key = "id")


# calculate summary variables for each group
t = proc.time()
dt3 = dt2[, .(N = .N,
              N2 = sum(value > 2)), by = id]
proc.time() - t

# user  system elapsed
# 1.93    0.00    1.94


# calculate summary variables for each group after creating a flag variable
t = proc.time()
dt3 = dt2[, flag := ifelse(value > 2, 1, 0)][, .(N = .N,
                                                 N2 = sum(flag)), by = id]
proc.time() - t

# user  system elapsed
# 0.33    0.04    0.39

最佳答案

dplyr的问题在于sum函数用于表达式和大量ID/组。 从Arun在评论中所说的,我想data.table的问题是相似的。

考虑下面的代码:我将其减少到了说明问题所必需的最低限度。即使表达式仅涉及标识函数,dplyr在对表达式求和时也很慢,因此性能问题与大于比较运算符无关。相反,在对向量求和时,dplyr很快。通过将ID/组的数量从一百万减少到十,可以实现更大的性能提升。

原因是hybrid evaluation(即C++中的求值)仅在将sum与向量一起使用时才有效。以表达式作为参数,评估在R中完成,这会增加每个组的开销。详细信息在链接的小插图中。从代码的配置文件来看,开销似乎主要来自tryCatch错误处理函数。

##########################
### many different IDs ###
##########################

df <- data.frame(id = 1:1e6, value = runif(1e6))

# sum with expression as argument
system.time(df %>% group_by(id) %>% summarise(sum(identity(value))))
#    user  system elapsed
#  80.492   0.368  83.251

# sum with vector as argument
system.time(df %>% group_by(id) %>% summarise(sum(value)))
#    user  system elapsed
#   1.264   0.004   1.279


#########################
### few different IDs ###
#########################

df$id <- rep(1:10, each = 1e5)

# sum with expression as argument
system.time(df %>% group_by(id) %>% summarise(sum(identity(value))))
#    user  system elapsed
#   0.088   0.000   0.093

# sum with vector as argument
system.time(df %>% group_by(id) %>% summarise(sum(value)))
#    user  system elapsed
#   0.072   0.004   0.077


#################
### profiling ###
#################

df <- data.frame(id = 1:1e6, value = runif(1e6))

profvis::profvis({ df %>% group_by(id) %>% summarise(sum(identity(value))) })

代码简介:

r - 计算每个组中某个条件为真的次数-LMLPHP

关于r - 计算每个组中某个条件为真的次数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39248216/

10-11 21:28