我正在尝试学习 R 并且我在 SAS 中做了 10 多年的一些事情,我无法弄清楚在 R 中做的最佳方法。拿这个数据:
id class t count desired
-- ----- ---------- ----- -------
1 A 2010-01-15 1 1
1 A 2010-02-15 2 3
1 B 2010-04-15 3 3
1 B 2010-09-15 4 4
2 A 2010-01-15 5 5
2 B 2010-06-15 6 6
2 B 2010-08-15 7 13
2 B 2010-09-15 8 21
我想按 id、class 和在 4 个月的滚动窗口内计算所需的列作为滚动总和。请注意,对于 id 和 class 的每个组合,并非所有月份都存在。
在 SAS 中,我通常会通过以下两种方式之一执行此操作:
RETAIN
加上一个by id & class。 PROC SQL
在适当的窗口中,在 id、class 和 df1.d-df2.d 上从 df as df1 到 df as df2 进行左连接 解决此类问题的最佳 R 方法是什么?
t <- as.Date(c("2010-01-15","2010-02-15","2010-04-15","2010-09-15",
"2010-01-15","2010-06-15","2010-08-15","2010-09-15"))
class <- c("A","A","B","B","A","B","B","B")
id <- c(1,1,1,1,2,2,2,2)
count <- seq(1,8,length.out=8)
desired <- c(1,3,3,4,5,6,13,21)
df <- data.frame(id,class,t,count,desired)
最佳答案
这里有几个解决方案:
1) 动物园使用 ave
, 为每个组创建一个每月系列,m
,通过合并原始系列,z
,带网格,g
.然后计算滚动总和,只保留原来的时间点:
library(zoo)
f <- function(i) {
z <- with(df[i, ], zoo(count, t))
g <- zoo(, seq(start(z), end(z), by = "month"))
m <- merge(z, g)
window(rollapplyr(m, 4, sum, na.rm = TRUE, partial = TRUE), time(z))
}
df$desired <- ave(1:nrow(df), df$id, df$class, FUN = f)
这使:
> df
id class t count desired
1 1 A 2010-01-15 1 1
2 1 A 2010-02-15 2 3
3 1 B 2010-04-15 3 3
4 1 B 2010-09-15 4 4
5 2 A 2010-01-15 5 5
6 2 B 2010-06-15 6 6
7 2 B 2010-08-15 7 13
8 2 B 2010-09-15 8 21
注意我们假设时间在每个组内排序(如问题中所示)。如果不是这样,那么排序
df
第一的。2) sqldf
library(sqldf)
sqldf("select id, class, a.t, a.'count', sum(b.'count') desired
from df a join df b
using(id, class)
where a.t - b.t between 0 and 100
group by id, class, a.t")
这使:
id class t count desired
1 1 A 2010-01-15 1 1
2 1 A 2010-02-15 2 3
3 1 B 2010-04-15 3 3
4 1 B 2010-09-15 4 4
5 2 A 2010-01-15 5 5
6 2 B 2010-06-15 6 6
7 2 B 2010-08-15 7 13
8 2 B 2010-09-15 8 21
注意:如果合并太大而无法放入内存,则使用
sqldf("...", dbname = tempfile())
使中间结果存储在它动态创建的数据库中,然后自动销毁。3) 底座 R sqldf 解决方案激发了这个基本的 R 解决方案,它只是将 SQL 转换为 R:
m <- merge(df, df, by = 1:2)
s <- subset(m, t.x - t.y >= 0 & t.x - t.y <= 100)
ag <- aggregate(count.y ~ t.x + class + id, s, sum)
names(ag) <- c("t", "class", "id", "count", "desired")
结果是:
> ag
t class id count desired
1 2010-01-15 A 1 1 1
2 2010-02-15 A 1 2 3
3 2010-04-15 B 1 3 3
4 2010-09-15 B 1 4 4
5 2010-01-15 A 2 5 5
6 2010-06-15 B 2 6 6
7 2010-08-15 B 2 7 13
8 2010-09-15 B 2 8 21
注意:这确实会在内存中进行合并,如果数据集非常大,这可能是一个问题。
更新:第一个解决方案的小幅简化,并添加了第二个解决方案。
更新 2:添加了第三个解决方案。
关于r - 通过 id 变量计算滚动总和,缺少时间点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16840101/