我沿着这些行有一组数据
d1 <- data.frame(
cat1 = sample(c('a', 'b', 'c'), 100, replace = TRUE),
date = rep(Sys.Date() - sample(1:100)),
val = rnorm(100, 50, 5)
)
require(data.table)
d2 <- data.table(d1)
我可以毫无问题地获得每日总和
d2[ , list(.N, sum(val)), by = c("cat1", "date")]
我希望得到超过2天(然后是7天)的总和
这有效:
d.list <- sort(unique(d2$date))
o.list <- list()
for(i in seq_along(d.list)){
o.list[[i]] <- d2[d2$date >= d.list[i] - 1 & d2$date <= d.list[i], list(.N, sum(val), max(date)), by = c("cat1")]
}
do.call(rbind, o.list)
但是放慢了更大的数据集,并且似乎不是数据的最佳用途。表。
有更有效的方法吗?
答案 0 :(得分:3)
这有点快:
首先我们加入完全匹配并获得最后一个索引(如果是多个匹配)
setkey(d2, cat1, date)
tmp1 = d2[unique(d2, by=key(d2)), which=TRUE, mult="last", allow.cartesian=TRUE]
然后,我们构建copy
d2
并通过引用将date
更改为date-1
。然后,我们使用roll=-Inf
执行联接 - 这是下一次向后观察。换句话说,如果没有完全匹配,它将填充下一个可用值。
d3 = copy(d2)[, date := date-1]
setkey(d3, cat1, date)
tmp2 = d2[unique(d3, by=key(d2)), roll=-Inf, which=TRUE, allow.cartesian=TRUE]
从这里开始,我们整理了指数:
idx1 = tmp1-tmp2+1L
idx2 = data.table:::vecseq(tmp2, idx1, sum(idx1))
来自d2
的子集idx2
并从idx1
生成唯一ID:
ans1 = d2[idx2][, grp := rep(seq_along(idx1), idx1)]
最后按grp
汇总并获得所需的结果:
ans1 = ans1[, list(cat1=cat1[1L], date=date[.N],
N = .N, val=sum(val)), by=grp][, grp:=NULL]
> head(ans1, 10L)
# cat1 date N val
# 1: a 2014-01-20 1 47.69178
# 2: a 2014-01-25 1 52.01006
# 3: a 2014-02-01 1 46.82132
# 4: a 2014-02-06 1 44.62404
# 5: a 2014-02-11 1 49.63218
# 6: a 2014-02-14 1 48.80676
# 7: a 2014-02-22 1 49.27800
# 8: a 2014-02-23 2 96.17617
# 9: a 2014-02-26 1 49.20623
# 10: a 2014-02-28 1 46.72708
结果与解决方案中的结果相同。这个在我的笔记本电脑上花了0.02秒,而你的笔记本电脑花了0.58秒。
连续7天,只需更改:
d3 = copy(d2)[, date := date-1]
到
d3 = copy(d2)[, date := date-6]
答案 1 :(得分:1)
OP在你想要的内容中解释得很糟糕,但这似乎就是这样:
# generate the [date-1,date] sequences for each date
# adjust length.out to suit your needs
dates = d2[, list(date.seq = seq(date, by = -1, length.out = 2)), by = date]
setkey(dates, date.seq)
setkey(d2, date)
# merge and extract info needed
dates[d2][, list(.N, sum(val), date.seq[.N]), by = list(date, cat1)][,
!"date", with = F]
# cat1 N V2 V3
# 1: a 1 38.95774 2014-01-21
# 2: a 1 38.95774 2014-01-21
# 3: c 1 55.68445 2014-01-22
# 4: c 2 102.20806 2014-01-23
# 5: c 1 46.52361 2014-01-23
# ---
#164: c 1 50.17986 2014-04-27
#165: b 1 51.43489 2014-04-28
#166: b 2 100.91982 2014-04-29
#167: b 1 49.48493 2014-04-29
#168: c 1 54.93311 2014-04-30
答案 2 :(得分:0)
是否可以设置分箱日期,然后对其进行by
?
d2$day7 <- as.integer(d2$date) %/% 7
d2[ , list(.N, sum(val)), by = c("cat1", "day7")]
这会给出一个分档值 - 如果你想要一个7天的滑动窗口,我需要再考虑一下。此外,对于分箱方法,如果要选择组开始的星期几,则可能需要在执行%/%之前减去偏移量。