计算一段时间后的累计和

Calculate cumulative sum after a set period of time

我有一个包含 COVID 数据的数据框,我正在尝试制作一个列,根据阳性测试的数量计算康复人数。

我的数据有位置、日期和每天的测试数量 administered/positive results/negative 结果。这里有几行以一个位置为例(真实数据有几个月的日期):

loc    date        tests  pos  neg  active
spot1  2020-04-10  1      1    0    5
spot1  2020-04-11  2      1    1    6
spot1  2020-04-12  0      0    0    6
spot1  2020-04-13  11     1    10   7

我想创建一个新列,在记录 14 天后累计计算每个位置的每个阳性测试。在 2020-04-24,5 个活动 类 不再活动,所以我想要一个包含 5 个的恢复列。对于每个日期,我都希望添加新的非活动案例。

我的第一个想法是循环尝试:

df1 <- df %>%
  mutate(date = as.Date(date)) %>%
  group_by(loc) %>%
  mutate(rec = for (i in 1:nrow(df)) {
  #getting number of new cases
  x <- df$pos[i]
  #add 14 days to the date
  d <- df$date + 14
  df$rec <- sum(x)
})

如您所见,我不是最擅长编写 for 循环的。这给了我一堆数字,但与数据没有什么有意义的关系。

也尝试过 map_dbl:

df1 <- df %>%
  mutate(date = as.Date(date)) %>%
  group_by(loc) %>%
  mutate(rec = map_dbl(date, ~sum(pos[(date <= . + 14) & date >= .])))

这导致在整个 rec 列上打印相同的数字。

有什么建议吗? (抱歉解释冗长,只是想确保这一切都有意义)

library(tidyverse)
library(lubridate)

data %>%
    mutate(date = as_date(date),
           cut = cut(date, '14 days') %>%
    group_by(loc) %>%
    arrange(cut) %>%
    mutate(cum_pos = accumulate(pos, `+`)) # accumulate(pos, sum) should also work

作为一般经验法则,避免循环,尤其是在 mutate 中——那是行不通的。你应该查看 purrr::accumulate 而不是 map_dbl。在 R 的基础库中有专门的函数,例如 cumsumcummin,但它们的行为与 purrr 的行为相比更难预测。

您可以使用聚合对特定列求和然后应用 cut 以便为每个金额设置 14 天的时间范围:

df <- data.frame(loc = rep("spot1", 30),
       date = seq(as.Date('2020-04-01'), as.Date('2020-04-30'),by = 1),
       test = seq(1:30),
       positive = seq(1:30),
       active = seq(1:30))

 output <- aggregate(positive ~ cut(date, "14 days"), df, sum)

 output 
 

控制台输出:

 cut(date, "14 days") positive
1           2020-04-01      105
2           2020-04-15      301
3           2020-04-29       59

我的解决方案:

library(dplyr)
date_seq <- seq(as.Date("2020/04/01"), by = "day", length.out = 30)
pos <- rpois(n = 60, lambda = 10)

mydf <-
  data.frame(loc = c(rep('loc1', 30), rep('loc2', 30)),
             date = date_seq,
             pos = pos)
head(mydf)

getPosSum <- function(max, tbl, myloc, daysBack = 14) {
  max.Date <- as.Date(max)
  sum(tbl %>%
        filter(date >= max.Date - (daysBack - 1) &
                 date <= max.Date & loc == myloc) %>%
        select(pos))
}

result <-
  mydf %>%
  group_by(date, loc) %>%
  mutate(rec = getPosSum(max = date, tbl = mydf, myloc = loc))

您的示例数据显示 -

  • 尽管 0 测试(4 月 12 日),您的所有日期都是连续的
  • Active 列似乎已经是 cumsum

因此我认为您可以简单地使用带有参数 14

lag 函数

示例代码

df %>% group_by(loc) %>% mutate(recovered = lag(active, 14)) %>% ungroup()