【发布时间】:2017-01-13 22:31:26
【问题描述】:
我有一个 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,然后使用来自 zoo 的 na.locf() 向后进行下一个观察:
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 解决方案?
【问题讨论】:
-
aggregate(dat, list(dat$day), mean)[, c('day', 'val')]做你想做的事吗? -
如果想在求平均值前用下一个值替换NA,可以直接赋值
dat[is.na(dat$val), ]$val <- dat[which(is.na(dat$val)) + 1, ]$val
标签: r data.table