【问题标题】:Converting ddply syntax into data.table将 ddply 语法转换为 data.table
【发布时间】:2013-05-11 06:52:02
【问题描述】:

我有一个 130 万行数据框,我需要将其汇总为区域和时间摘要。 Plyr 的语法很简单,但它太慢了,不实用(我让ddply 运行了一个小时,它完成了不到 25%)。我正在寻求帮助,将 ddply 语法翻译成 data.table 以利用其自诩的速度。

我的数据属于以下类型

library(plyr)
library(lubridate)

dat <- expand.grid(area = letters[1:2],
                    day = as.Date("2012-10-01") + c(0:10) * days(1),
                   type = paste("t", 1:2, sep=""))
dat$val <- runif(44)

我需要不同时期的行数(根据我的玩具数据,这里将是相等的)和 val 变量的总和。

这个ddply 电话给了我我正在寻找的东西

count.and.sum <- function(i){
  if(i$day >= as.Date("2012-10-02")){
     k <- data.frame(c_1d = nrow(dat[dat$type == i$type &
                                     dat$area == i$area &
                                     dat$day %in% i$day - days(1),]),
                     c_2d = nrow(dat[dat$type == i$type &
                                     dat$area == i$area &
                                     dat$day %in% (i$day - c(1:2) * days(1)),]),
                     s_1d = sum(dat$val[dat$type == i$type &
                                        dat$area == i$area &
                                        dat$day %in% i$day - days(1)]),
                     s_2d = sum(dat$val[dat$type == i$type &
                                        dat$area == i$area &
                                        dat$day %in% (i$day - c(1:2) * days(1))]))
  return(k) 
  }
 }

ddply(dat, .(area, day, type), count.and.sum)[1:10,]

非常感谢您提供的任何 data.table 语法。

【问题讨论】:

  • 查看 data.table 的 .SD 参数

标签: r data.table plyr


【解决方案1】:

首先,您的函数非常低效,并且对传递给 plyr 的函数应该是什么样子缺乏了解。对于 ddply(),它应该将一个通用数据帧作为输入并输出一个数据帧。在这种情况下,“通用”是指将生成为由分组变量的级别组合定义的任何“拆分”的数据框。你的函数应该看起来更像这样:

count.and.sum <- function(d) data.frame(n = length(d$val), valsum = sum(d$val))

在 ddply() 调用中处理分组变量组合。

其次,您的 ddply() 调用会创建一行数据框,因为每个观察结果都与区域、日期和类型的唯一组合相关联。对于这个玩具示例,ddply() 的更实际应用是按天进行总结:

使用summarise 作为“应用”函数的直接方法:

ddply(dat, .(day), summarise, nrow = length(val), valsum = sum(val))

使用count.and.sum

ddply(dat, .(day), count.and.sum)

这很可能比您的count.and.sum 版本快得多。

至于等效的 data.table 版本(不一定是最有效的),试试这个:

library(data.table)
DT <- data.table(dat, key = c('area', 'day', 'type'))

DT[, list(n = length(val), valsum = sum(val)), by = 'day']

这是一个稍微复杂的玩具示例,包含 10 万个观察值:

set.seed(5490)
dat2 <- data.frame(area = sample(letters[1:2], 1e5, replace = TRUE),
                   day = sample(as.Date("2012-10-01") + c(0:10) * days(1),
                                  1e5, replace = TRUE),
                   type = sample(paste0("t", 1:2), 1e5, replace = TRUE),
                   val = runif(1e5))

system.time(u <- ddply(dat2, .(area, day, type), summarise, 
                      n = length(val), valsum = sum(val)))

DT2 <- data.table(dat2, key = c('area', 'day', 'type'))
system.time(v <- DT2[, list(n = length(val), valsum = sum(val)), by = key(DT)])

identical(u, as.data.frame(v))

在我的系统上,data.table 版本比plyr 版本快大约 4.5 倍(plyr 用了 0.09 秒,data.table 用了 0.02 秒)。

【讨论】:

  • 在 data.table 中使用 .N 而不是 length(val)
猜你喜欢
  • 2015-02-16
  • 1970-01-01
  • 2012-04-12
  • 2019-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多