1

我有一个 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您可以提供的任何语法。

4

1 回答 1

2

首先,您的函数效率极低,并且对传递给 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 秒)。

于 2013-05-11T08:58:47.390 回答