【问题标题】:How to get the ending date from the first observation and use it as the starting date for the second observation for the same ID?如何从第一次观察中获取结束日期并将其用作同一 ID 的第二次观察的开始日期?
【发布时间】:2019-08-08 10:08:36
【问题描述】:

我的 df 有一些独特的和一些双重的条目和列,显示每个观察的开始和结束日期,但它们不能重叠相同的 id。


df <- data.frame(id = c(22,22,102,102,102),
                 start_date = as.Date(c("2013-10-29","2014-01-09",
                                 "2016-09-14",
                                 "2016-09-14","2016-09-14")), 
                 end_date = as.Date(c("2017-08-15","2018-10-05",
                                 "2016-10-09",
                                 "2017-12-12","2018-10-17")))

head(df)
   id start_date   end_date
1  22 2013-10-29 2017-08-15
2  22 2014-01-09 2018-10-05
3 102 2016-09-14 2016-10-09
4 102 2016-09-14 2017-12-12
5 102 2016-09-14 2018-10-17

ids 22 和 102 日期间隔重叠,但对于 22 具有不同的 start_date 而对于 102 具有相同的 start_date。

我需要的结果是:

  1. 当日期重叠时,以上次观察的最后日期作为开始日期。
  2. 当日期不重叠时,保留实际值。

有什么想法或建议吗?

我期望的结果是:

head(fixed_df)
   id start_date   end_date
1  22 2013-10-29 2017-08-15
2  22 2017-08-15 2018-10-05
3 102 2016-09-14 2016-10-09
4 102 2016-10-09 2017-12-12
5 102 2017-12-12 2018-10-17

【问题讨论】:

    标签: r date


    【解决方案1】:

    在 R 中,您可以轻松地将日期对象与普通 ==、> 或

    #Loop over every lines except the last one
    for (line in c(1:(length(df$id)-1)))
    {
      #Do something only if next line have the same ID
      if(df$id[line]==df$id[line+1])
      {
        #Check if end date is after start date of the next line
        if(df$end_date[line]>df$start_date[line+1])
        {
         #If yes, put the start date of next line to end date of current line
         df$start_date[line+1]=df$end_date[line]
        }
      }
    
    
    }
    

    【讨论】:

    • 谢谢,Chelmy88。它工作得很好,尤其是以前做的安排(id,start_date,end_date)。它比 dplyr 的选项更快(我一直是首选,但通常更慢)。
    【解决方案2】:

    有了dplyr,我会这样做:

    library(dplyr)
    df %>% group_by(id) %>%
      arrange(start_date) %>%
      mutate(
        lag(end_date),
        overlap = start_date < lag(end_date, default=as.Date('2000-01-01')),
        new_start_date = if_else(overlap, lag(end_date), start_date)
      )
    
         id start_date end_date   `lag(end_date)` overlap new_start_date
      <dbl> <date>     <date>     <date>          <lgl>   <date>        
    1    22 2013-10-29 2017-08-15 NA              FALSE   2013-10-29    
    2    22 2014-01-09 2018-10-05 2017-08-15      TRUE    2017-08-15    
    3   102 2016-09-14 2016-10-09 NA              FALSE   2016-09-14    
    4   102 2016-09-14 2017-12-12 2016-10-09      TRUE    2016-10-09    
    5   102 2016-09-14 2018-10-17 2017-12-12      TRUE    2017-12-12   
    

    这个非常冗长,但只是为了演示正在发生的事情。

    一些关键点:

    1. 使用group_by 将比较保持在id 内。
    2. 接下来,排序。
    3. lag - 与之前的值进行比较。但是使用一个好的默认值,也就是同一类型。

    如果您想要严格无重叠,请考虑使用lag(end_date) + days(1)

    【讨论】:

    • 谢谢,Gumble 先生。它工作得很好,尤其是同时使用arrange(id, start_date, end_date)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-27
    • 2023-03-23
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 2022-01-08
    相关资源
    最近更新 更多