【问题标题】:find the sum after every seventh day but with missing days in R在每七天之后找到总和,但在 R 中缺少天数
【发布时间】:2021-07-20 01:24:58
【问题描述】:

我有一个如下的 R df:

| date_entered | returning | new |
| ------------ | --------- | --- |
| 2021-06-02   |         0 |  14 |
| 2021-06-03   |        12 |   8 |
| 2021-06-04   |         8 |   0 |
| 2021-06-05   |         7 |  15 |
| 2021-06-07   |        10 |   4 |
| 2021-06-08   |        12 |  22 |
| 2021-06-09   |         4 |  15 |
| 2021-06-10   |         0 |  28 |
| 2021-06-12   |        22 |  16 |
| 2021-06-15   |        20 |   5 |
| 2021-06-16   |        18 |  12 |
| 2021-06-17   |         2 |  10 |
| 2021-06-18   |        12 |   8 |

  • 请注意,缺少日期。我需要在每 7 天之后从上面找到“新”列的总和,如下所示:
| date_range              | sum_new |
| ----------------------- | ------- |
| 2021-06-02 - 2021-06-08 |      53 |
| 2021-06-09 - 2021-06-15 |      49 |
| 2021-06-16 - 2021-06-22 |      30 |

我尝试了以下方法:

library(zoo)
n <- 7
rollapply(df$new, n, sum, by = n)

但它会忽略日期,只是在 df 的每七个值之后添加

| sum_new |
| ------- |
|      78 |
|      79 |

这不是我想要得到的。

【问题讨论】:

  • 最好在数据的最后提供代码,即dput(df)
  • 因为我的问题是如何高效地复制然后将数据导入 R。

标签: r sum zoo rollapply


【解决方案1】:

您可以使用cut 将数据集划分为7 天间隔,sumnew 值。

library(dplyr)

df %>%
  group_by(group = cut(date_entered, '7 days')) %>%
  summarise(date_range = paste(min(date_entered), min(date_entered) + 6, sep = '-'), 
            sum_new = sum(new)) %>%
  select(-group)

#  date_range            sum_new
#  <chr>                   <int>
#1 2021-06-02-2021-06-08      63
#2 2021-06-09-2021-06-15      64
#3 2021-06-16-2021-06-22      30

【讨论】:

    【解决方案2】:

    我们假设最后的注释中显示的输入可重现。

    去掉返回的列,转换成zoo,它也把字符日期转换成Date类,然后再转换成ts。转换为 ts 将插入缺失的日期,为这些日期提供新的 NA 值。然后将其转换回 zoo 并用 0 填充 NA。接下来使用 rollapply。我们向左对齐并使用 partial=TRUE 以便包括最后的部分周。出现的日期将是每 7 天间隔的开始。因为 ts 不能表示 Date 类,所以时间将是数字,因此使用聚合将它们转换回 Date,将总和作为动物园对象 sum_new。可以选择将其转换为数据框(或省略它并仅使用 sum_new)。

    library(zoo)
    
    sum_new <- df |>
      subset(select = -returning) |>
      read.zoo() |>
      as.ts() |>
      as.zoo() |>
      na.fill(0) |>
      rollapply(7, by = 7, sum, partial = TRUE, align = "left") |>
      aggregate(as.Date)
    
    fortify.zoo(sum_new, name = "date")
    

    给予:

            date sum_new
    1 2021-06-02      63
    2 2021-06-09      64
    3 2021-06-16      30
    

    注意

    df <-
    structure(list(date_entered = c("2021-06-02", "2021-06-03", "2021-06-04", 
    "2021-06-05", "2021-06-07", "2021-06-08", "2021-06-09", "2021-06-10", 
    "2021-06-12", "2021-06-15", "2021-06-16", "2021-06-17", "2021-06-18"
    ), returning = c(0L, 12L, 8L, 7L, 10L, 12L, 4L, 0L, 22L, 20L, 
    18L, 2L, 12L), new = c(14L, 8L, 0L, 15L, 4L, 22L, 15L, 28L, 16L, 
    5L, 12L, 10L, 8L)), class = "data.frame", row.names = c(NA, -13L
    

    【讨论】:

      【解决方案3】:

      我的解决方案是按您的范围对date_entered 进行分组,然后求和
      每个组。

      dt %>% 
          group_by(dr = findInterval(date_entered, as.Date(c("2021-06-09", "2021-06-16")))) %>%
          summarise(sum_new = sum(new))
      

      data.table

      dt <- fread("
      date_entered  returning  new 
      2021-06-02            0   14 
      2021-06-03           12    8 
      2021-06-04            8    0 
      2021-06-05            7   15 
      2021-06-07           10    4 
      2021-06-08           12   22 
      2021-06-09            4   15 
      2021-06-10            0   28 
      2021-06-12           22   16 
      2021-06-15           20    5 
      2021-06-16           18   12 
      2021-06-17            2   10 
      2021-06-18           12    8 ")
      
      dt[,.(sum_new = sum(new)), by = .(dr = findInterval(date_entered, as.Date(c("2021-06-09", "2021-06-16"))))]
      

      【讨论】:

      • 试试:fi &lt;- function(x) findInterval(x, seq(x[1]+7, tail(x, 1), 7)); df %&gt;% group_by(g = fi(as.Date(date_entered))) %&gt;% summarize(date = max(date_entered), sum_new = sum(new)) %&gt;% select(-g)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-12
      • 1970-01-01
      • 2011-06-13
      • 2021-08-07
      • 1970-01-01
      相关资源
      最近更新 更多