将ddply语法转换为data.table

时间:2013-05-11 06:52:02

标签: r data.table plyr

我有一个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语法。

1 个答案:

答案 0 :(得分:2)

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

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

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

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

使用summarise作为'apply'函数的直接方法:

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']

这是一个稍微复杂的玩具示例,带有100K观测值:

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)。