将连续日期的行转换为日期范围列

时间:2017-11-13 21:34:03

标签: r dataframe

我必须在某些日期将满足条件,二元标志的观测值转换为具有日期范围的观测表。

示例数据如下所示:

id <- c(1001, 1001, 1001, 1002, 1002, 1002, 1003, 1003, 1003)
date <- c("2016-06-20", "2016-06-21", "2016-06-22", "2016-06-20", 
          "2016-06-21", "2016-06-22", "2016-06-20", "2016-06-21", 
          "2016-06-22")
flag <- c(1, 0, 0, 1, 1, 0, 1, 0, 1)
mydata <- data.frame(id, date, flag)

  id       date flag
1001 2016-06-20    1
1001 2016-06-21    0
1001 2016-06-22    0
1002 2016-06-20    1
1002 2016-06-21    1
1002 2016-06-22    0
1003 2016-06-20    1
1003 2016-06-21    0
1003 2016-06-22    1

我认为这是一个两步过程。

步骤1:确定标志是否连续出现。

这与此问题类似 - R, find, dates, consecutive - 但条件是flag > 0。我尝试应用解决方案,虽然它的工作方式不同。

mydata$flag_consecutive <- mydata$flag > 0 & c(NA, diff(as.Date(mydata$date)) == 1)


  id       date flag flag_consecutive
1001 2016-06-20    1               NA
1001 2016-06-21    0            FALSE
1001 2016-06-22    0            FALSE
1002 2016-06-20    1            FALSE
1002 2016-06-21    1             TRUE
1002 2016-06-22    0            FALSE
1003 2016-06-20    1            FALSE
1003 2016-06-21    0            FALSE
1003 2016-06-22    1             TRUE

第2步:创建日期范围列

我不确定如何在R中使用矢量化来处理这个部分。 如果标志仅在一天发生,则开始和结束日期相同。 如果该标志连续几天发生,我希望将序列中的第一天作为date_start,将最后一天作为date_end。如果没有发生标记,请从数据集中删除该标记。

我想要生成的是以这种方式格式化的数据:

  id flag  date_start     date_end
1001    1  2016-06-20   2016-06-20
1002    1  2016-06-20   2016-06-21
1003    1  2016-06-20   2016-06-20
1003    1  2016-06-22   2016-06-22

如果您可以就第1步或第2步提供任何指导,我非常感谢。我在圈子里思考,不确定是否需要第1步。

1 个答案:

答案 0 :(得分:2)

使用data.table - 包的可能解决方案:

library(data.table)
setDT(mydata)[, rl := rleid(flag)
              ][flag == 1
                , .(date_start = first(date), date_end = last(date))
                , by = .(id, rl, flag)
                ][, rl := NULL][]

给出:

     id flag date_start   date_end
1: 1001    1 2016-06-20 2016-06-20
2: 1002    1 2016-06-20 2016-06-21
3: 1003    1 2016-06-20 2016-06-20
4: 1003    1 2016-06-22 2016-06-22

这是做什么的:

  • rl := rleid(flag)rl s的每个连续行创建分组变量flag
  • 使用flag == 1
  • 过滤
  • 使用`by =。(id,rl,flag)
  • 分组
  • 使用.(date_start = first(date), date_end = last(date))选择每个组的第一个和最后一个观察值;当只有一个值时,firstlast会选择该值。

使用dplyr的等效方法:

library(dplyr)
mydata %>% 
  mutate(rl = cumsum(flag != lag(flag, default = 1))) %>% 
  filter(flag == 1) %>% 
  group_by(id, flag, rl) %>% 
  summarise(date_start = first(date),
            date_end = last(date)) %>% 
  select(-rl)