【问题标题】:Add column to table with values depending on dates将列添加到表中,其值取决于日期
【发布时间】:2018-05-07 17:29:09
【问题描述】:

我有一个表格,其中包含日期作为数字和每个日期的值。现在我想添加另一列weekSum,其中包含上周的价值总和。但是缺少一些日期(所以我不能总是使用当前和最后 6 行)。我的桌子是这样的:

df <- data.frame('date' = c(20160309, 20160310, 20160311, 20160312, 20160313, 20160314, 20160315, 20160317, 20160318, 20160319, 20160321), 'value' = c(1, 2, 3, 4, 5, 6, 7 ,8, 9, 10, 11))

date        value
20160309     1
20160310     2
20160311     3
20160312     4
20160313     5
20160314     6
20160315     7
20160316     8     
20160318     9     #17th skipped
20160319    10     
20160321    11     #20th skipped

我想得到以下输出:

date        value    weekSum
20160309     1       NA
20160310     2       NA
20160311     3       NA
20160312     4       NA
20160313     5       NA
20160314     6       NA
20160315     7       28    # 1+2+3+4+5+6+7
20160316     8       35    # 2+3+4+5+6+7+8
20160318     9       39    # 4+5+6+7+8+9
20160319    10       45    # 5+6+7+8+9+10
20160321    11       45    # 7+8+9+10+11

如何做到这一点?

【问题讨论】:

  • 为什么开头的 weekSum 的值不见了?它不应该被填充吗?

标签: r sum


【解决方案1】:

1) 将数据框转换为 zoo 并定义一个 weekSum 函数,该函数将其输入子集到上周并将其相加。然后将rollapplyrcoredata = FALSE 一起使用,以便将带有时间的动物园对象(不仅仅是核心数据)传递给weekSum 函数。

library(zoo)

z <- read.zoo(df, format = "%Y%m%d")
weekSum <- function(z) sum(z[time(z) > tail(time(z), 1) - 7])
transform(df, weekSum = rollapplyr(z, 7, weekSum, fill = NA, coredata = FALSE))

给予:

               date value weekSum
2016-03-09 20160309     1      NA
2016-03-10 20160310     2      NA
2016-03-11 20160311     3      NA
2016-03-12 20160312     4      NA
2016-03-13 20160313     5      NA
2016-03-14 20160314     6      NA
2016-03-15 20160315     7      28
2016-03-16 20160316     8      35
2016-03-18 20160318     9      39
2016-03-19 20160319    10      45
2016-03-21 20160321    11      45

2) 另一种方法是用零填充缺失日期的值,然后使用宽度为 7 的 rollsumrz 来自 (1)。

z0 <- merge(z, zoo(, seq(start(z), end(z), "day")), fill = 0)
transform(df, weekSum = rollsumr(z0, 7, fill = NA)[z0 != 0])

【讨论】:

  • 谢谢,这很好用!您能否解释一下以下部分的工作原理?我认为它是创建过去一周的某种矢量/列表,但我不太明白如何。 tail(time(z), 1) - 7
  • rollapplyr 将最后 7 个点作为动物园对象 z 传递,对于任何动物园对象,我们可以使用 time(z) 获取其时间。 tail(time(z), 1) 是过去的最后(当前)时间。 read.zoo 创建了一个 zoo 对象,其时间属于 "Date" 类,对于任何 "Date" 类对象,我们可以通过减去 7 得到 7 天前。
  • 再次感谢!我还有一个问题,希望你能为我解答。由于您没有指定有关行的任何内容,weeksum 怎么知道它应该取值的总和而不是日期的总和?
  • z 不是数据框。它是一个动物园对象,在这种情况下是一个值向量,其时间索引存储为属性。诸如"ts""zoo" 类之类的时间序列对象的想法是,可以在不考虑时间索引的情况下处理值,并且时间索引会自动处理(对齐、子集化)。在 R 命令行中输入 z 以查看它的外观。也可以试试str(z)dput(z)。建议查看 zoo 附带的 5 个小插曲及其帮助文件。
  • 试试rollapplyr(z0, 7, sum, partial = TRUE)
【解决方案2】:

使用基础 R 可以这样做:

res <- merge(df, data.frame(date = seq(df$date[1], to = df$date[length(d)], by = "days")), all.y = TRUE)

res$weekSum <- NA
for(i in seq_along(res$sum)[-seq_len(6)]){
    res$weekSum[i] <- sum(res$value[(i - 6):i], na.rm = TRUE)
}
res <- res[!is.na(res$value), ]
res
#         date value sum weekSum
#1  2016-03-09     1  NA      NA
#2  2016-03-10     2  NA      NA
#3  2016-03-11     3  NA      NA
#4  2016-03-12     4  NA      NA
#5  2016-03-13     5  NA      NA
#6  2016-03-14     6  NA      NA
#7  2016-03-15     7  28      28
#9  2016-03-17     8  33      35
#10 2016-03-18     9  39      42
#11 2016-03-19    10  45      49
#13 2016-03-21    11  45      56

【讨论】:

    【解决方案3】:

    这是一种使用tidyverse 工具的方法。此方法使用tidyr::complete 来构造完整的日期序列,从而可以轻松地按照建议获取当前行和前 6 行。如果有,请注意这里 以value 中的NA 值开头,因为目前这些行将在最后被过滤掉。如有必要,可以进行调整以避免这种情况。

    library(tidyverse)
    library(lubridate)
    #> 
    #> Attaching package: 'lubridate'
    #> The following object is masked from 'package:base':
    #> 
    #>     date
    df <- data.frame('date' = c(20160309, 20160310, 20160311, 20160312, 20160313, 20160314, 20160315, 20160317, 20160318, 20160319, 20160321), 'value' = c(1, 2, 3, 4, 5, 6, 7 ,8, 9, 10, 11))
    df %>%
      mutate(date = ymd(date)) %>%
      complete(date = seq.Date(min(date), max(date), by = 1)) %>%
      arrange(date) %>%
      mutate(
        newval = replace_na(value, 0),
        weekSum = newval + lag(newval) + lag(newval, 2) + lag(newval, 3) +
          lag(newval, 4) + lag(newval, 5) + lag(newval, 6)
      ) %>%
      select(-newval) %>%
      filter(!is.na(value))
    #> # A tibble: 11 x 3
    #>    date       value weekSum
    #>    <date>     <dbl>   <dbl>
    #>  1 2016-03-09    1.     NA 
    #>  2 2016-03-10    2.     NA 
    #>  3 2016-03-11    3.     NA 
    #>  4 2016-03-12    4.     NA 
    #>  5 2016-03-13    5.     NA 
    #>  6 2016-03-14    6.     NA 
    #>  7 2016-03-15    7.     28.
    #>  8 2016-03-17    8.     33.
    #>  9 2016-03-18    9.     39.
    #> 10 2016-03-19   10.     45.
    #> 11 2016-03-21   11.     45.
    

    reprex package (v0.2.0) 于 2018 年 5 月 7 日创建。

    【讨论】:

      猜你喜欢
      • 2022-01-26
      • 1970-01-01
      • 1970-01-01
      • 2018-06-28
      • 2016-11-04
      • 1970-01-01
      • 1970-01-01
      • 2017-12-02
      • 2010-12-17
      相关资源
      最近更新 更多