R-(Tidyverse)将多个观测值压缩为一个

doc*_*jay 3 r lubridate dplyr tidyverse

我有一个包含多个变量的数据集,其中两个是日期(开始日期,结束日期)。有时,日期间隔已分成多个序列,例如,您将有:

开始:1990-12-12,停止:1990-12-13开始:1990-12-13,停止:1990-12-14

而不是

开始:1990-12-12,停止:1990-12-14

我要做的是隔离这些序列链,并将它们基本上折叠成一个观察值,这样就保存了序列末尾的所有观察值,其余的则被覆盖(第一个开始日期除外)。以下是一个基本示例:

library(tidyverse)
library(lubridate)

tib_ex <- tibble(
  id = rep(1,5),
  date1 = ymd(c('1990-11-05', '1990-12-01', 
                '1990-12-05', '1990-12-08', 
                '1990-12-15')),
  date2 = ymd(c('1990-11-28', '1990-12-05', 
                '1990-12-08', '1990-12-12', 
                '1990-12-31')),
  var1 = 2:6,
  var2 = 7:11,
  var3 = 12:16,
  var4 = c(0, 1, 0 ,0, 1)
)
Run Code Online (Sandbox Code Playgroud)

这将产生以下提示:

# A tibble: 5 x 7
     id date1      date2       var1  var2  var3  var4
  <dbl> <date>     <date>     <int> <int> <int> <dbl>
1     1 1990-11-05 1990-11-28     2     7    12     0
2     1 1990-12-01 1990-12-05     3     8    13     1
3     1 1990-12-05 1990-12-08     4     9    14     0
4     1 1990-12-08 1990-12-12     5    10    15     0
5     1 1990-12-15 1990-12-31     6    11    16     1
Run Code Online (Sandbox Code Playgroud)

我想将其转换为以下标题:

# A tibble: 3 x 7
     id date1      date2       var1  var2  var3  var4
  <dbl> <chr>      <chr>      <dbl> <dbl> <dbl> <dbl>
1     1 1990-11-05 1990-11-28     2     7    12     0
2     1 1990-12-01 1990-12-12     5    10    15     0
3     1 1990-12-15 1990-12-31     6    11    16     1
Run Code Online (Sandbox Code Playgroud)

我考虑过按id,date1和date2嵌套,这会将其余变量打包为每行小标题,从而易于覆盖,我只是不知道如何有效地折叠第2行到第4行的日期。

我尝试创建一个二进制变量,该变量可跟踪一个观察的结束日期是否与以下观察的开始日期匹配,但是我也遇到了麻烦。

AEF*_*AEF 6

通过与下一行/上一行进行比较来查找具有开始日期和结束日期的行,并以合适的方式合并结果:

date_info <- 
  tib_ex %>% 
  ## find indices of start and end dates by comparing with date in next / previous row
  mutate(is_startdate = date1 != lag(date2),
         is_enddate = date2 != lead(date1)) %>% 
  ## NA's appear at the beginning (start_date) and end (end_date) and should thus be interpreted as TRUE
  replace_na(list(is_startdate = T, is_enddate = T))

## combine the start- and end-dates
date_info %>% 
  filter(is_enddate) %>% 
  mutate(date1 = date_info$date1[date_info$is_startdate]) %>% 
  select(-starts_with("is_"))

-------
# A tibble: 3 x 7
id date1      date2       var1  var2  var3  var4
<dbl> <date>     <date>     <int> <int> <int> <dbl>
1  1.00 1990-11-05 1990-11-28     2     7    12  0   
2  1.00 1990-12-01 1990-12-12     5    10    15  0   
3  1.00 1990-12-15 1990-12-31     6    11    16  1.00
Run Code Online (Sandbox Code Playgroud)