代码之家  ›  专栏  ›  技术社区  ›  Bart Spoon

将重叠时间范围的数据转换为不同时间范围的数据

  •  1
  • Bart Spoon  · 技术社区  · 6 年前

    我有一些数据,包括对某个人申请某一特定状态的时间范围的观察。一个人在给定的时间可以有多个状态,或者根本没有状态(在这种情况下,不会有观察)。

    ID  STATUS START      END    
    1   A      2013-03-07 2013-04-20
    1   B      2013-04-10 2013-05-10
    1   C      2013-04-16 2013-07-11
    1   B      2013-07-25 2013-08-08
    2   A      2013-09-10 2014-04-21
    2   C      2013-12-27 2014-01-26
    2   D      2014-04-28 2014-05-10
    2   E      2014-05-11 2014-07-16
    

    我想把它转换成一个数据框架,由不同的、不重叠的周期和在这些周期中应用的所有状态组成。示例的结果如下。

    ID  STATUS START      END    
    1   A      2013-03-07 2013-04-10
    1   A,B    2013-04-10 2013-04-16
    1   A,B,C  2013-04-16 2013-04-20
    1   B,C    2013-04-20 2013-05-10
    1   C      2013-05-10 2013-07-11
    1   B      2013-07-25 2013-08-08
    2   A      2013-09-10 2013-12-27
    2   A,C    2013-12-27 2014-01-26
    2   D      2014-04-28 2014-05-10
    2   E      2014-05-11 2014-07-16
    

    我的数据相当大,所以我努力寻找一种有效的方法来做到这一点。我发现了一些半相关的问题,比如 here 但它们通常涉及到将重叠区域折叠成一个超级区域,而不是将它们分割成不同的子区域。

    任何帮助或想法都会受到赞赏。谢谢。

    1 回复  |  直到 6 年前
        1
  •  2
  •   C. Braun    6 年前
    library(dplyr)
    
    # Create all the possible date ranges
    date_breaks <- sort(c(df$START, df$END))
    
    # Build a data.frame with all possible combinations
    df2 <- expand.grid(START = head(date_breaks, -1),
                       ID = unique(df$ID),
                       STATUS = unique(df$STATUS),
                       stringsAsFactors = F)
    df2$END <- tail(date_breaks, -1)
    
    # Join in original data and filter to where the start and end are in range
    df2 %>%
        inner_join(df, by = c("ID", "STATUS")) %>%
        filter(START.y <= START.x, END.y >= END.x) %>%
        group_by(ID, START = START.x, END = END.x) %>%
        summarise(STATUS = paste(unique(STATUS), collapse = ', ')) %>% 
        select(ID, STATUS, START, END)
    
    #  A tibble: 11 x 4
    #  Groups:   ID, START [11]
    #       ID STATUS  START      END       
    #    <int> <chr>   <date>     <date>    
    #  1     1 A       2013-03-07 2013-04-10
    #  2     1 A, B    2013-04-10 2013-04-16
    #  3     1 A, B, C 2013-04-16 2013-04-20
    #  4     1 B, C    2013-04-20 2013-05-10
    #  5     1 C       2013-05-10 2013-07-11
    #  6     1 B       2013-07-25 2013-08-08
    #  7     2 A       2013-09-10 2013-12-27
    #  8     2 A, C    2013-12-27 2014-01-26
    #  9     2 A       2014-01-26 2014-04-21
    # 10     2 D       2014-04-28 2014-05-10
    # 11     2 E       2014-05-11 2014-07-16
    

    数据

    df <- read.table(text = "ID  STATUS START      END    
                             1   A      2013-03-07 2013-04-20
                             1   B      2013-04-10 2013-05-10
                             1   C      2013-04-16 2013-07-11
                             1   B      2013-07-25 2013-08-08
                             2   A      2013-09-10 2014-04-21
                             2   C      2013-12-27 2014-01-26
                             2   D      2014-04-28 2014-05-10
                             2   E      2014-05-11 2014-07-16",
                     header = T,
                     colClasses = c('integer', 'character', 'Date', 'Date'))