r - 通过 id 变量计算滚动总和,缺少时间点

标签 r sas plyr zoo

我正在尝试学习 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/

    相关文章:

    r - Shiny模块之间的通信

    r - Bloomberg API 报价回顾监视器

    random - 如何在SAS宏中包含do循环?

    r - 嵌套 ifelse 语句

    r - ddply 用于 R 中的回归

    r - 分组相关矩阵

    r - 需要具有开始停止索引的更快的滚动应用功能

    r - 你能告诉我这个错误是什么意思吗?

    r - 使用 dplyr 拟合多个 nls 函数

    mysql - 从 Win XP 升级到 Win 7,现在无法运行处理 MySQL 数据库的 SAS 脚本