【问题标题】:R: merge Dataframes on date and unique IDs with conditions distributed across many rows in RR:合并日期和唯一ID的数据框,条件分布在R中的多行
【发布时间】:2019-12-23 18:31:34
【问题描述】:

我正在尝试基于与唯一标识符关联但分布在不同观察值(行)中的几个日期之间的条件关系合并两个数据框。

我有两个具有唯一标识符的大型数据集。一个数据集具有“进入”和“退出”日期(以及其他一些变量)。

> df1 <- data.frame(ID=c(1,1,1,2,2,3,4), 
enter.date=c('5/07/2015','7/10/2015','8/25/2017','9/1/2016','1/05/2018','5/01/2016','4/08/2017'), 
+                   exit.date = c('7/1/2015', '10/15/2015', '9/03/2017', '9/30/2016', '6/01/2019', 
'5/01/2017', '6/08/2017'));
> dcis <- grep('date$',names(df1));
> df1[dcis] <- lapply(df1[dcis],as.Date,'%m/%d/%Y');
> df1;
  ID enter.date  exit.date
1  1 2015-05-07 2015-07-01
2  1 2015-07-10 2015-10-15
3  1 2017-08-25 2017-09-03
4  2 2016-09-01 2016-09-30
5  2 2018-01-05 2019-06-01
6  3 2016-05-01 2017-05-01
7  4 2017-04-08 2017-06-08

另一个有“评估”日期。

> df2 <- data.frame(ID=c(1,2,2,3,4), eval.date=c('10/30/2015', 
'10/10/2016','9/10/2019','5/15/2018','1/19/2015'));
> df2$eval.date<-as.Date(df2$eval.date, '%m/%d/%Y')
> df2;
  ID  eval.date
1  1 2015-10-30
2  2 2016-10-10
3  2 2019-09-10
4  3 2018-05-15
5  4 2015-01-19

我正在尝试计算数据集中每个人从“退出”到“评估”的平均时间间隔。但是,我只想要在给定个人的“退出”之后和该个人的下一个“进入”之前的那些“评估”(在给定个人的进入和退出之间没有“评估”观察),如果这样的'评估'存在。

换句话说,我试图从上面的两个数据帧中得到一个看起来像这样的输出。

> df3 <- data.frame(ID=c(1,2,2,3), enter.date=c('7/10/2015','9/1/2016','1/05/2018','5/01/2016'), 
+                   exit.date = c('10/15/2015', '9/30/2016', '6/01/2019', '5/01/2017'),
+                   assess.date=c('10/30/2015', '10/10/2016', '9/10/2019', '5/15/2018'));
> dcis <- grep('date$',names(df3));
> df3[dcis] <- lapply(df3[dcis],as.Date,'%m/%d/%Y');
> df3$time.diff<-difftime(df3$exit.date, df3$assess.date)
> df3;
  ID enter.date  exit.date assess.date time.diff
1  1 2015-07-10 2015-10-15  2015-10-30  -15 days
2  2 2016-09-01 2016-09-30  2016-10-10  -10 days
3  2 2018-01-05 2019-06-01  2019-09-10 -101 days
4  3 2016-05-01 2017-05-01  2018-05-15 -379 days

一旦我执行合并,使用

找到平均值就很容易了
> aggregate(df3[,5], list(df3$ID), mean)
  Group.1       x
1       1  -15.0 
2       2  -55.5 
3       3 -379.0

但我真的不知道如何执行合并。我尝试使用leftjoin 和fuzzyjoin 根据herehere 给出的建议执行合并,但我对R 缺乏经验,无法弄清楚。如果有人能指导我完成它,我将不胜感激 - 谢谢!

关于数据的其他一些描述性说明:每个 ID 在每个数据帧中可能有一些与其关联的行。 df1 具有标记服务交付开始的输入日期和标记服务交付结束的退出日期。所有的入口都有一个对应的出口。 df2 有评估日期。评估日期可以在个人接受服务的任何时间出现。在一个服务交付周期和下一个服务交付周期之间可能有许多评估,或者可能没有评估。

【问题讨论】:

    标签: r date merge


    【解决方案1】:

    刚刚发现了 sqldf 包。假设每个 ID 的日期范围都按升序排列,您可以像这样使用它:

    df1 <- data.frame(ID=c(1,1,1,2,2,3,4), enter.date=c('5/07/2015','7/10/2015','8/25/2017','9/1/2016','1/05/2018','5/01/2016','4/08/2017'), exit.date = c('7/1/2015', '10/15/2015', '9/03/2017', '9/30/2016', '6/01/2019', 
    '5/01/2017', '6/08/2017'));
    dcis <- grep('date$',names(df1));
    df1[dcis] <- lapply(df1[dcis],as.Date,'%m/%d/%Y');
    df1;
    
    df2 <- data.frame(ID=c(1,2,2,3,4), eval.date=c('10/30/2015', 
    '10/10/2016','9/10/2019','5/15/2018','1/19/2015'));
    df2$eval.date<-as.Date(df2$eval.date, '%m/%d/%Y')
    df2;
    
    library(sqldf)
    
    df1 = unsplit(lapply(split(df1, df1$ID, drop=FALSE), function(df) {
        df$next.date = as.Date('2100-12-31')
        if (nrow(df) > 1)
            df$next.date[1:(nrow(df) - 1)] = df$enter.date[2:nrow(df)]
        df
    }), df1$ID)
    
    
    sqldf('
    select df1.*, df2.*, df1."exit.date" - df2."eval.date" as "time.diff"
      from df1, df2
      where df1.ID == df2.ID
        and df2."eval.date" between df1."exit.date"
        and df1."next.date"')
    
    
      ID enter.date  exit.date  next.date ID..5  eval.date time.diff
    1  1 2015-07-10 2015-10-15 2017-08-25     1 2015-10-30       -15
    2  2 2016-09-01 2016-09-30 2018-01-05     2 2016-10-10       -10
    3  2 2018-01-05 2019-06-01 2100-12-31     2 2019-09-10      -101
    4  3 2016-05-01 2017-05-01 2100-12-31     3 2018-05-15      -379
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-02
      • 2020-07-04
      • 2018-11-25
      • 1970-01-01
      • 1970-01-01
      • 2021-02-03
      • 2021-09-10
      • 1970-01-01
      相关资源
      最近更新 更多