【问题标题】:Finding Cumulative Sum In R Using Conditions使用条件在 R 中查找累积和
【发布时间】:2017-07-11 13:49:52
【问题描述】:

我需要创建一个新变量,其中包含每个 ID 过去三年金额的总和。

如果没有三年的数据,应该有一个“NA”。

举个例子:

ID YEAR   AMOUNT
1 2010      5
1 2011      2
1 2012      4
1 2013      1
1 2014      3
2 2013      4
2 2014      6
2 2015      9
3 2012      4
3 2013      7
3 2014      2
3 2015      3

结果应该是这样的:

ID YEAR AMOUNT THREE_YR
1 2010      5       NA
1 2011      2       NA
1 2012      4       11
1 2013      1        7
1 2014      3        8
2 2013      4       NA
2 2014      6       NA
2 2015      9       19
3 2012      4       NA
3 2013      7       NA
3 2014      2       13
3 2015      3       12

我该怎么做?谢谢!

【问题讨论】:

  • zoo::rollsum

标签: r sum


【解决方案1】:

我们可以使用dplyrzoo 中的函数。 dt2 是最终输出。

# Create example data frame
dt <- read.table(text = "ID YEAR   AMOUNT
1 2010      5
                 1 2011      2
                 1 2012      4
                 1 2013      1
                 1 2014      3
                 2 2013      4
                 2 2014      6
                 2 2015      9
                 3 2012      4
                 3 2013      7
                 3 2014      2
                 3 2015      3",
                 header = TRUE, stringsAsFactors = FALSE)

# Load packages
library(dplyr)
library(zoo)

# Process the data
dt2 <- dt %>%
  group_by(ID) %>%
  mutate(THREE_YR = rollsum(AMOUNT, k = 3, fill = NA, align = "right"))

更新:ID 组少于 3 条记录。

OP 询问如果只有一两行的 ID 该怎么办。老实说,我没有找到解决这个问题的好方法。我唯一能想到的是将原始数据框分为两组,将rollsum 应用于所有记录大于或等于三的组。之后,合并所有组。

# Create example data frame
dt <- read.table(text = "ID YEAR   AMOUNT
                 1 2010      5
                 1 2011      2
                 1 2012      4
                 1 2013      1
                 1 2014      3
                 2 2013      4
                 3 2012      4
                 3 2013      7
                 3 2014      2
                 3 2015      3",
                 header = TRUE, stringsAsFactors = FALSE)

# Load packages
library(dplyr)
library(zoo)

# Process the data
dt2 <- dt %>%
  group_by(ID) %>%
  filter(n() >= 3) %>%
  mutate(THREE_YR = rollsum(AMOUNT, k = 3, fill = NA, align = "right")) %>%
  bind_rows(dt %>% group_by(ID) %>% filter(n() < 3)) %>%
  arrange(ID, YEAR)

【讨论】:

  • 谢谢!我收到一个错误:“mutate_impl(.data, dots) 中的错误:评估错误:k
  • 你说的是示例数据集还是你的真实数据集?对于某些 ID 组,您可能只获得一两条记录。对于这些 ID,rollsum 将失败。
  • 正确。在我的真实数据集中,有一些 ID 组只有一两条记录。知道在这种情况下什么会起作用吗?
  • 尝试将mutate 调用改为:mutate(THREE_YR = ifelse(n() &gt;= 3, rollsum(AMOUNT, k = 3, fill = NA, align = "right"), NA))
  • 这种变异在 THREE_YR 列中直接产生 NA...[在我发送的数据集中,假设 ID 2 只有一行。]再次感谢!
【解决方案2】:

data.table

library(data.table)
setDT(dt)
setorder(dt,YEAR)
dt[,.(YEAR,AMOUNT,THREE_YR=AMOUNT+shift(AMOUNT,1)+shift(AMOUNT,2)),by=.(ID)]
#ID YEAR AMOUNT THREE_YR
# 1:  1 2010      5       NA
# 2:  1 2011      2       NA
# 3:  1 2012      4       11
# 4:  1 2013      1        7
# 5:  1 2014      3        8
# 6:  3 2012      4       NA
# 7:  3 2013      7       NA
# 8:  3 2014      2       13
# 9:  3 2015      3       12
#10:  2 2013      4       NA
#11:  2 2014      6       NA
#12:  2 2015      9       19

【讨论】:

    【解决方案3】:

    使用zoo::rollapplyr()aggregate()
    如果组中的成员少于三个,这将返回 NA

    x <- structure(list(ID = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 
      3L, 3L), YEAR = c(2010L, 2011L, 2012L, 2013L, 2014L, 2013L, 2014L, 
      2015L, 2012L, 2013L, 2014L, 2015L), AMOUNT = c(5L, 2L, 4L, 1L, 
      3L, 4L, 6L, 9L, 4L, 7L, 2L, 3L)), .Names = c("ID", "YEAR", "AMOUNT"
      ), class = "data.frame", row.names = c(NA, -12L))
    
    library(zoo)
    
    rsum <- aggregate(AMOUNT ~ ID, data=x, 
      FUN=function(x) rollapplyr(x, 3, fill=NA, partial=TRUE,
      FUN=function(y) if (length(y) >= 3) sum(y) else NA))
    
    x$rsum <- do.call(c, rsum$AMOUNT)
    x
    #    ID YEAR AMOUNT rsum
    # 1   1 2010      5   NA
    # 2   1 2011      2   NA
    # 3   1 2012      4   11
    # 4   1 2013      1    7
    # 5   1 2014      3    8
    # 6   2 2013      4   NA
    # 7   2 2014      6   NA
    # 8   2 2015      9   19
    # 9   3 2012      4   NA
    # 10  3 2013      7   NA
    # 11  3 2014      2   13
    # 12  3 2015      3   12
    
    # remove one of the 2s
    x <- x[-6, ]
    
    rsum <- aggregate(AMOUNT ~ ID, data=x, 
      FUN=function(x) rollapplyr(x, 3, fill=NA, partial=TRUE,
      FUN=function(y) if (length(y) >= 3) sum(y) else NA))
    
    
    x$rsum <- do.call(c, rsum$AMOUNT)
    x
    #    ID YEAR AMOUNT rsum
    # 1   1 2010      5   NA
    # 2   1 2011      2   NA
    # 3   1 2012      4   11
    # 4   1 2013      1    7
    # 5   1 2014      3    8
    # 7   2 2014      6   NA
    # 8   2 2015      9   NA
    # 9   3 2012      4   NA
    # 10  3 2013      7   NA
    # 11  3 2014      2   13
    # 12  3 2015      3   12
    

    【讨论】:

      猜你喜欢
      • 2013-05-20
      • 1970-01-01
      • 2022-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-05
      相关资源
      最近更新 更多