【问题标题】:R function for creating uneven groups based on uneven dates用于基于不均匀日期创建不均匀组的 R 函数
【发布时间】:2021-07-30 19:39:49
【问题描述】:

我试图找到一个 R 函数,它可以迭代地索引组,给定一组不均匀间隔的日期、不均匀的组大小和分组情况。以下是示例数据:

> h
# A tibble: 20 x 2
      ID date      
   <int> <date>    
 1     1 2021-01-07
 2     1 2021-01-11
 3     1 2021-01-15
 4     1 2021-01-16
 5     1 2021-01-21
 6     1 2021-01-26
 7     1 2021-02-04
 8     1 2021-02-08
 9     1 2021-02-13
10     1 2021-02-20
11     1 2021-02-23
12     1 2021-02-27
13     2 2021-01-05
14     2 2021-01-11
15     2 2021-02-02
16     2 2021-02-08
17     2 2021-02-08
18     2 2021-02-14
19     2 2021-02-17
20     2 2021-02-21

对于每个唯一的ID,我想找到第一个日期(按时间顺序)并为该案例和 7 天内的任何其他行创建一个组(即group==1)。对于下一个日期 7 天后,在接下来的 7 天内为该案例和任何其他案例创建第二个组(即group==2)。注意:下一个日期不一定是初始日期后的 7 天。对剩余的情况重复此过程以获得所需的输出:

# A tibble: 20 x 3
      ID date       group
   <int> <date>     <dbl>
 1     1 2021-01-07     1
 2     1 2021-01-11     1
 3     1 2021-01-15     2
 4     1 2021-01-16     2
 5     1 2021-01-21     2
 6     1 2021-01-26     3
 7     1 2021-02-04     4
 8     1 2021-02-08     4
 9     1 2021-02-13     5
10     1 2021-02-20     5
11     1 2021-02-23     6
12     1 2021-02-27     6
13     2 2021-01-05     1
14     2 2021-01-11     1
15     2 2021-02-02     2
16     2 2021-02-08     2
17     2 2021-02-08     2
18     2 2021-02-14     3
19     2 2021-02-17     3
20     2 2021-02-21     3

据我所知,使用 7 天的滚动窗口函数不起作用,因为它会错误地对案例进行分组。但我想知道是否可以使用一种 custom 滚动窗口功能?我更喜欢使用dplyr 的解决方案,但其他选项也可以。感谢您提供任何帮助。

> dput(h)
structure(list(ID = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), date = structure(c(18634, 
18638, 18642, 18643, 18648, 18653, 18662, 18666, 18671, 18678, 
18681, 18685, 18632, 18638, 18660, 18666, 18666, 18672, 18675, 
18679), class = "Date")), row.names = c(NA, -20L), class = c("tbl_df", 
"tbl", "data.frame"))

【问题讨论】:

    标签: r date dplyr grouping


    【解决方案1】:

    定义一个函数 date1,它给出了前一行点的组的第一个日期,当前行的日期返回当前组的开始日期——这必须是两个参数之一。然后按 ID 分组,使用 Reduce 将其应用于每个 ID 中的日期,并将结果转换为因子,然后转换为整数。

    library(dplyr)
    
    date1 <- function(prev, x) if (x > prev + 7) x else prev
    h %>% 
      group_by(ID) %>%
      mutate(group = as.integer(factor(Reduce(date1, date, acc = TRUE)))) %>%
      ungroup
    

    给予:

    # A tibble: 20 x 3
          ID date       group
       <int> <date>     <dbl>
     1     1 2021-01-07     1
     2     1 2021-01-11     1
     3     1 2021-01-15     2
     4     1 2021-01-16     2
     5     1 2021-01-21     2
     6     1 2021-01-26     3
     7     1 2021-02-04     4
     8     1 2021-02-08     4
     9     1 2021-02-13     5
    10     1 2021-02-20     5
    11     1 2021-02-23     6
    12     1 2021-02-27     6
    13     2 2021-01-05     1
    14     2 2021-01-11     1
    15     2 2021-02-02     2
    16     2 2021-02-08     2
    17     2 2021-02-08     2
    18     2 2021-02-14     3
    19     2 2021-02-17     3
    20     2 2021-02-21     3
    

    【讨论】:

    • 太棒了!这对示例数据和我的其他测试数据非常有效。谢谢!
    【解决方案2】:

    对于每个 ID 组,创建 group 作为 NA 向量。虽然一些 group 元素仍然是 NA,但取第一个日期值 group 是 NA 并添加 0 和 7 天以形成日期范围。对于 date 在计算日期范围内的任何行,将 group 的元素设置为比 group 的当前最大值大 1(如果 group 仍然是全部 NA,则设置为 0)。

    library(data.table)
    setDT(df)
    
    df[order(ID, date), {
         group <- rep(NA_real_, .N)
         while(any(is.na(group))){
           group_range <- first(date[is.na(group)]) + c(0, 7)
           group[date %between% group_range] <- 1 + max(fcoalesce(group, 0)) 
         }
         list(date, group) 
       }, by = ID]
    
    # ID       date group
    # 1:  1 2021-01-07     1
    # 2:  1 2021-01-11     1
    # 3:  1 2021-01-15     2
    # 4:  1 2021-01-16     2
    # 5:  1 2021-01-21     2
    # 6:  1 2021-01-26     3
    # 7:  1 2021-02-04     4
    # 8:  1 2021-02-08     4
    # 9:  1 2021-02-13     5
    # 10:  1 2021-02-20     5
    # 11:  1 2021-02-23     6
    # 12:  1 2021-02-27     6
    # 13:  2 2021-01-05     1
    # 14:  2 2021-01-11     1
    # 15:  2 2021-02-02     2
    # 16:  2 2021-02-08     2
    # 17:  2 2021-02-08     2
    # 18:  2 2021-02-14     3
    # 19:  2 2021-02-17     3
    # 20:  2 2021-02-21     3
    

    这是我尝试限制计算的另一个版本。不知道它是否真的更快

    df[order(ID, date), {
         group <- rep(NA_integer_, .N)
         i <- 1L
         g <- 1L
         while(i <= .N){
           group_range <- date[i] + c(0, 7)
           chg <- date %between% group_range
           group[chg] <- g
           g <- g + 1L
           i <- i + sum(chg)
         }
         list(date, group) 
       }, by = ID]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-20
      • 2014-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-04
      • 2018-02-06
      相关资源
      最近更新 更多