【问题标题】:Number of continuous weeks by group分组连续周数
【发布时间】:2019-06-05 03:19:47
【问题描述】:

如何按组查找连续周数,但从数据集中的最大日期开始计算?

假设我有这个数据框:

  id       Week
1   A  2/06/2019
2   A 26/05/2019
3   A 19/05/2019
4   A 12/05/2019
5   A  5/05/2019
6   B  2/06/2019
7   B 26/05/2019
8   B 12/05/2019
9   B  5/05/2019
10  C 26/05/2019
11  C 19/05/2019
12  C 12/05/2019
13  D  2/06/2019
14  D 26/05/2019
15  D 19/05/2019
16  E  2/06/2019
17  E 19/05/2019
18  E 12/05/2019
19  E  5/05/2019

我想要的输出是:

id count
1:  A     5
2:  B     2
3:  D     3
4:  E     1

我目前正在将日期转换为因子以获取订购编号并检查根据每组中的行数创建的参考编号。

library(data.table)
df <- structure(list(id = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
                                      2L, 3L, 3L, 3L, 4L, 4L, 4L, 5L, 5L, 5L, 5L), 
                                    .Label = c("A", "B", "C", "D", "E"), class = "factor"), 
                     Week = structure(c(3L, 4L, 2L, 1L, 5L, 3L, 4L, 1L, 5L, 4L, 2L, 1L, 3L, 4L, 2L, 3L, 2L, 1L, 5L), 
                                      .Label = c("12/05/2019", "19/05/2019", "2/06/2019", "26/05/2019", "5/05/2019"), class = "factor")), 
                class = "data.frame", row.names = c(NA, -19L))
dt <- data.table(df)
dt[, Week_no := as.factor(as.Date(Week, format = "%d/%m/%Y"))]
dt[, Week_no := factor(Week_no)]
dt[, Week_no := as.numeric(Week_no)]

max_no <- max(dt$Week_no)
dt[, Week_ref := max_no:(max_no - .N + 1), by = "id"]
dt[, Week_diff := Week_no - Week_ref]
dt[Week_diff == 0, list(count = .N), by = "id"]

【问题讨论】:

  • lubridate::week 可能有用

标签: r data.table


【解决方案1】:

这是一种方法:

dt <- dt[, Week := as.Date(Week, format = "%d/%m/%Y")]
ids_having_max <- dt[.(max(Week)), id, on = "Week"]
dt <- dt[.(ids_having_max), on = "id"
         ][order(-Week), .(count = sum(rleid(c(-7L, diff(Week))) == 1)), by = "id"]

分成几个步骤:

我们将Week 保留为日期,因为它已经可以进行比较, 并且您可以减去日期来获得时差。

然后我们得到所有包含整个表中最大日期的ids。 这是使用secondary indices

我们再次使用二级索引来过滤掉那些 属于先前结果的ids (dt[.(ids_having_max), on = "id" 部分)。

最后一帧很棘手。 我们按id 分组,并确保行按Week 降序排列。 那么逻辑如下。

当你有连续的几周时, diff(Week) 在所选排序中始终为 -7。 计算diff 返回一个较短的向量,因为第一个结果是通过从第二个输入元素中减去第一个输入元素来计算的, 所以我们在前面加上 -7 以确保它是 rleid 输入中的第一个元素。

对于rleid,我们将 1 分配给第一个 -7 并保持 1 直到我们看到与 -7 不同的东西。 不同的东西意味着周不再是连续的。 sum(rleid(c(-7L, diff(Week))) == 1) 将简单地返回 rleid 等于 1 的行数。

B 的最后一部分示例:

  • 差异:-7, -14, -7
  • 在添加 -7 之后:-7, -7, -14, -7
  • rleid之后:1, 1, 2, 3
  • 从上一个,两个有一个rleid == 1

【讨论】:

    【解决方案2】:

    dplyr 解决方案道歉,但我认为data.table 可以更简洁地实现类似的方法。

    library(dplyr)
    df$Week = lubridate::dmy(df$Week)
    df %>%
      group_by(id) %>%
      arrange(id, Week) %>%
      # Assign group to each new streak
      mutate(new_streak = cumsum(Week != lag(Week, default = 0) + 7)) %>%
      add_count(id, new_streak) %>%
      slice(n()) # Only keep last week
    

    【讨论】:

    • 感谢dplyr 解决方案,总是能找到替代方案。
    【解决方案3】:

    所以我建议将数据列的格式转换为显示周数"%W",如下所示

    dt[, Week_no := format(as.Date(Week, format = "%d/%m/%Y"),"%W")]
    

    然后找出每个 id 值的唯一周数数量

    dt[,(length(unique(Week_no))),by="id"]
    

    全面披露

    我意识到,当我运行此程序时,我得到的表与你现在的表不同,因为 R 会逐周计算给定年份的周数。

    如果这不能回答您的问题,请告诉我,我可以尝试更新

    【讨论】:

    • 谢谢,但这不起作用,因为问题更多是关于如何找到连续周数而不是唯一周数。
    猜你喜欢
    • 2023-03-12
    • 1970-01-01
    • 2014-02-08
    • 2016-01-31
    • 1970-01-01
    • 2014-11-17
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多