【问题标题】:R: dplyr group by date rangeR:dplyr 按日期范围分组
【发布时间】:2016-09-22 13:55:58
【问题描述】:

我正在尝试根据“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的输出,只有一些观察结果属于这个类别,否则,都是NAs
  • df %&gt;% group_by(dr = cut(date, breaks = c(min(date), as.Date(c("2016-04-10", "2016-04-24")), max(date) + 1))) %&gt;% summarise(ost = sum(ost))?

标签: r group-by dplyr


【解决方案1】:

你可以先创建一个分组变量,

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

【讨论】:

  • 您可以将group列与mutate(group = cumsum(grepl('2016-04-10|2016-04-24', df$date)))内联
  • 感谢@Sotos。有用!您介意解释一下 cumsum 如何创建组吗?
  • @woshishui 使用grepl 创建一个逻辑向量。累积和只是将 FALSE = 0 和 TRUE = 1 的向量的值相加。
【解决方案2】:

我们使用cut 创建一个分组变量“dr”。提到的breaks 是“日期”的range,即“日期”的minmax 值以及OP 指定的日期,将其连接起来(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

注意:OP 询问了关于cut 的问题,这个解决方案给出了这个问题。

【讨论】:

  • 你能解释一下第一个吗?这是我最初的想法,您使用 %>% 将 df 传递给 group_by 然后 group_by 有两个参数,它将 df 转换为组。在 group_by 中,您使用 cut 将 numeric 更改为 cut(x, breaks,include.lowest = TRUE) 的因子。 x 是日期(因为我们希望将数据按 date 分组,breaks 给出了日期将被削减的间隔。我不知道为什么你使用 as.Date 和 include.lowest=TRUE 表示如果 date最低,则应用于休息。
  • 那么 this 的输出将再次通过 %>% 传递给新函数,并且 summarise(ost = sum(ost)) 显示输出列的总和。我理解正确吗?
  • 谢谢!我喜欢您的帖子,我将阅读您为人们提供的所有有价值的解决方案,我认为这对我很有帮助
  • @Learner %&gt;% 是连接左轴和右轴的管道或链运算符。我使用了as.Date,因为我们将另外两个日期元素作为character 向量传递。 include.lowest 默认为 FALSE。根据文档logical, indicating if an ‘x[i]’ equal to the lowest (or highest, for right = FALSE) ‘breaks’ value should be included.
  • 感谢 akrun,特别是指出 findInterval 函数。
猜你喜欢
  • 2013-11-04
  • 2021-11-16
  • 2013-05-19
  • 2010-10-31
  • 2019-02-19
  • 2019-02-14
  • 2015-01-03
相关资源
最近更新 更多