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

时间:2018-08-24 18:54:16

标签: r dataframe range overlap

我有一些数据,其中包括对特定状态适用于个人的时间范围的观察。一个人在给定的时间可以具有多种状态,或者根本没有任何统计信息(在这种情况下将没有观察值)。

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 个答案:

答案 0 :(得分:2)

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'))