dplyr按日期范围分组

11

我正在尝试根据"2016-04-10"和"2016-04-24"将数据框按照3个日期范围进行分组。

df <- structure(list(date = structure(c(16803, 16810, 16817, 16824, 
16831, 16838, 16845, 16852, 16859, 16866, 16873, 16880, 16887, 
16894, 16901, 16908, 16915, 16922, 16929, 16936, 16943), class = "Date"), 
    new = c(1507L, 2851L, 3550L, 5329L, 7557L, 5546L, 6264L, 
    7160L, 9468L, 5789L, 5928L, 4642L, 8145L, 4867L, 4846L, 5231L, 
    7137L, 3938L, 3741L, 2937L, 194L), resolved = c(21, 27, 15, 
    16, 56, 2773, 8490, 8748, 9325, 7734, 10264, 6739, 6110, 
    9613, 10314, 10349, 7200, 9637, 10831, 11170, 5666), ost = c(1486, 
    2824, 3535, 5313, 7501, 2773, -2226, -1588, 143, -1945, -4336, 
    -2097, 2035, -4746, -5468, -5118, -63, -5699, -7090, -8233, 
    -5472)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-21L), .Names = c("date", "new", "resolved", "ost"))

尝试了以下方法:

df1 <- df %>% group_by(dr=cut(date,breaks=as.Date(c("2016-04-10","2016-04-24")))) %>%
                summarise(ost = sum(ost))

这会导致以下错误结果。

        dr    ost
2016-04-10 -10586
        NA -17885

需要帮助!


如果您查看“cut”输出,只有一些观测值属于该类别,否则全部为NA。 - akrun
df %>% 按照 cut(date, breaks = c(min(date), as.Date(c("2016-04-10", "2016-04-24")), max(date) + 1)) 进行分组 %>% 汇总(ost = sum(ost)) - alistaire
2个回答

10
我们使用 cut创建了一个分组变量 'dr'。所提到的breaks是 'date' 的范围,即 'date' 的最小值和最大值以及由操作员指定的日期,将它们连接起来 (c),使用选项 include.lowest ,并根据此分组变量获取 'ost' 的 sum
df %>%
  group_by(dr = cut(date, breaks = c(range(date), 
            as.Date(c("2016-04-10", "2016-04-24"))), include.lowest=TRUE) ) %>% 
  summarise(ost =sum(ost))
#         dr    ost
#     <fctr>  <dbl>
#1 2016-01-03   8672
#2 2016-04-10 -10586
#3 2016-04-24 -26557

或者另一种选择是findInterval,与cut相比速度可能更快。

df %>%
  group_by(dr = findInterval(date, as.Date(c("2016-04-10", "2016-04-24")))) %>% 
  summarise(ost = sum(ost))
#     dr    ost
#  <int>  <dbl>
#1     0   8672
#2     1 -10586
#3     2 -26557

注意:提问者询问了有关 cut 的问题,并且这个解决方案就是针对此问题的。


请问您能解释一下第一个吗?首先,您可以使用%>%将df传递给group_by,然后有两个参数用于group_by,将df转换为组。在group_by中,您使用cut将数字转换为因子,即cut(x,breaks,include.lowest = TRUE)。x是日期(因为我们希望按日期分组数据),breaks是要切割日期的间隔。我不知道为什么接下来要使用as.Date和include.lowest = TRUE表示如果日期最低,则应用于断点。 - user6376316
然后,这个输出将再次通过 %>% 传递给新函数,并且 summarise(ost = sum(ost)) 显示 out 列的总和。我的理解是正确的吗? - user6376316
当然,我会添加描述。 - akrun
1
谢谢!我喜欢你的帖子,我打算阅读你给人们提供的所有有价值的解决方案,我认为这对我很有帮助。 - user6376316
1
@Learner %>% 是一个管道或链式操作符,它将 lhs 与 rhs 连接起来。我使用 as.Date 是因为我们正在传递两个日期元素作为 character 向量。include.lowest 默认为 FALSE。根据文档,它是“逻辑值,指示是否应包括等于最低(或最高,对于 right = FALSE)‘breaks’ 值的 ‘x[i]’”。 - akrun
1
感谢akrun,特别是指出findInterval函数。 - woshishui

7
你可以先创建一个分组变量,
df %>% 
mutate(group = cumsum(grepl('2016-04-10|2016-04-24', date))) %>%
group_by(group) %>% 
summarise(ost = sum(ost))

#Source: local data frame [3 x 2]

#  group    ost
#  (int)  (dbl)
#1     0   8672
#2     1 -10586
#3     2 -26557

1
您可以使用mutate(group = cumsum(grepl('2016-04-10|2016-04-24', df$date)))命令在行内添加group列。 - alistaire
谢谢@Sotos。它有效了!您介意解释一下cumsum如何工作以创建组吗? - woshishui
1
通过使用 grepl 函数,您可以创建一个逻辑向量。累积和函数 cumulative sum 只是将该向量的值相加,其中 FALSE = 0,TRUE = 1。 - Sotos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接