高效填写data.table列的(locf / nocb)值,然后由另一列聚合

时间:2017-01-13 22:31:26

标签: r data.table

我有一个data.table,其中包含一列客户ID,他们进行购买的天数列以及一个具有该购买价值的列。我想要做的是计算每个客户每天购买价值的平均值,用下一个可用值填充缺失值。

为简单起见,我在最小的例子中没有重复的日子。

library(data.table)
dat <- data.table(custid=rep(seq(10),5), day=sample(50), val=rnorm(50,0,1))[order(custid,day)]

现在,我知道如何解决这个问题,但我不知道如何有效地解决这个问题。一种解决方案是扩展data.table,使缺失值变为NA,然后使用na.locf()中的zoo向后进行下一次观察:

library(zoo)
res <- dat[as.data.table(expand.grid(custid=seq(10), day=seq(50))), on=c('custid','day'), allow.cartesian=TRUE, nomatch=NA][order(custid,day)]
res[, val:=na.locf(val, fromLast=TRUE, na.rm=FALSE), by='custid']
res <- res[,list(meanVal=mean(val, na.rm=TRUE)), by='day']

但是,当有很多天和很多客户时,这会创建一个非常大的表,但大多数客户只在极少数时间内购买。所以我不希望这样。

另一种解决方案是循环使用,每天过滤和聚合,然后再将行绑定到data.table中:

res2 <- list()
for (dy in seq(max(dat$day))) {
    res2 <- c(res2, 
              list(dat[day>=dy, .SD[1], by='custid'][,list(day=dy, meanVal=mean(val, na.rm=T))]))
}
res2 <- rbindlist(res2)

然而,这很慢。

有没有人能想出一个既不需要慢速循环也不需要创建大型中间表的data.table解决方案?

1 个答案:

答案 0 :(得分:3)

在我的有限测试中,这比你的任何一个选项都要快(顺便说一下使用<p-dialog header="Alert Dialog" [(visible)]="display" modal="modal" width="300" responsive="true"> <header> Header content here </header> Content <footer> Footer content here </footer> </p-dialog> 而不是CJ),并且不会占用太多内存:

data.table(expand.grid

这假设数据按日排序,如OP。