首页 > 解决方案 > 如何在日期之间合并

问题描述

我有 2 个如下所示的数据框:

df1
       ID   Drugname                    Startdate    Enddate     Dose   
      <dbl> <chr>                       <date>       <date>      <chr>    
1   111xxx  LAMISIL CREME 10MG/G        2008-04-04  2008-04-12  2. DA   
2   111xxx  LAMISIL CREME 10MG/G        2009-07-05  2009-07-12  2. AB   
3   111xxx  LAMISIL CREME 5MG/G         2009-11-22  2009-12-05  2. AB   
4   111xxx  TERBINAFINE TABL 250MG      2009-07-06  2009-08-11  1.1T    
5   111xxx  CLOZAPINE TABL 25MG         2005-06-01  2005-06-28  N 2T    
6   111xxx  CLOZAPINE TABL 25MG         2005-07-01  2005-07-28  N 2T    
7   222xxx  MAGNESIUM HYD KAUWT 724MG   2000-04-11  2000-04-24  1.1T    
8   222xxx  MAGNESIUM HYD KAUWT 724MG   2012-03-17  2012-03-25  1.1T    
etc.
df2
       ID    (...) DATE_RESULT v1    v2      
1:   111xxx        2007-11-28  <NA>  165   
2:   111xxx        2009-07-08  <NA>  105 
3:   222xxx        2009-08-24  <NA>  125         
4:   222xxx        2012-03-27    66  20       
etc. 

我想合并df1df2看起来像这样:

       ID    (...) DATE_RESULT v1    v2   Drugname1 Drugname2   NearDrug
1:   111xxx        2007-11-28  <NA>  165  NA        NA          NA
2:   111xxx        2009-07-08  <NA>  105  LAMISIL   TERBINAFINE NA
3:   222xxx        2009-08-24  <NA>  125  NA        NA          NA
4:   222xxx        2012-03-27    66  20   NA        NA          MAGNESIUM
etc. 

ID只想DATE_RESULTdf2介于StartdateEnddate之间时合并这些df1。由于IDs 可以有多个Drugnames,我希望它们彼此合并在同一行中,如新 df 的第 2 行所示。

然后我想要另一个合并/列(我不知道这是否可能),我ID只想在inDATE_RESULT之后df2最多 7 天时合并,创建列,如新 df 的第 4 行所示。Enddatedf1Neardrug

对于第一个问题,我已经尝试过:r merge by id and date between two dates,但这并没有给我我想要的新数据框,而且我太菜鸟了,无法更改该代码。

我想保留所有数据df2而不是df1. 由于显而易见的原因,所有信息都已被更改。

标签: rdatemerge

解决方案


那好吧!让我们将您的问题分为两部分。第一部分是按日期执行所述连接,第二部分是将许多结果分布在列上,而不是行上。

第 1 部分 虽然data.table可以解决问题,但我建议使用sqldfwhich 允许您使用 SQL 语法,如果您想更改逻辑条件或使其更复杂,该语法更具可读性、直观性和可扩展性。

library(data.table)
library(sqldf)

setDT(df1)
setDT(df2)
result <- sqldf("
  select 
    df2.*,
    df1.Drugname,
    case
      when df1.ID is null then NULL
      when df2.DATE_RESULT between df1.Startdate and df1.Enddate then 'Drugname' 
      else 'Neardrug' 
    end as situation
    from df2
    left join df1
      on df1.ID = df2.id 
        and df2.DATE_RESULT between df1.Startdate and date(df1.Enddate, '+7 days')
")

print(result)
      ID DATE_RESULT v1  v2                  Drugname situation
1 111xxx  2007-11-28 NA 165                      <NA>      <NA>
2 111xxx  2009-07-08 NA 105      LAMISIL CREME 10MG/G  Drugname
3 111xxx  2009-07-08 NA 105    TERBINAFINE TABL 250MG  Drugname
4 222xxx  2009-08-24 NA 125                      <NA>      <NA>
5 222xxx  2012-03-27 66  20 MAGNESIUM HYD KAUWT 724MG  Neardrug

如您所见,查询已经返回一个名为 的列situation,它可以是“Drugname”或“Neardrug”。

第 2 部分 现在您希望将同一 ID 的多行结果展开成列。理想的格式是将它们保持原样,在行和列的数据框中,没有重复的列。这被称为tidy格式,它通常被 R 中的几个库用作标准,具有几个优点。

因此,我们可以将列宽格式视为打印输出的格式,以使其更具可读性。还有其他担忧。如果您的栏目过多且内容过长,则可能会变得难以管理。但是,让我们去做吧。

为了做到这一点,我们首先需要将“药物名称”的情况创建为“药物名称1”、“药物名称2”等的序列名称。“Neardrug”->“Neardrug1”、“Neardrug2”等也是如此。

library(dplyr)

sequenced_result <- result %>%
  arrange(ID, DATE_RESULT, situation, Drugname) %>%
  group_by(ID, situation) %>%
  mutate(sequencing = row_number()) %>%
  mutate(colname = ifelse(is.na(situation), "Drugname1", paste0(situation, sequencing))) %>%
  ungroup()


print(sequenced_result)
  ID     DATE_RESULT    v1    v2 Drugname                  situation sequencing colname  
  <chr>  <chr>       <dbl> <dbl> <chr>                     <chr>          <int> <chr>    
1 111xxx 2007-11-28     NA   165 NA                        NA                 1 Drugname1
2 111xxx 2009-07-08     NA   105 LAMISIL CREME 10MG/G      Drugname           1 Drugname1
3 111xxx 2009-07-08     NA   105 TERBINAFINE TABL 250MG    Drugname           2 Drugname2
4 222xxx 2009-08-24     NA   125 NA                        NA                 1 Drugname1
5 222xxx 2012-03-27     66    20 MAGNESIUM HYD KAUWT 724MG Neardrug           1 Neardrug1

我们快到了。现在我们需要做的就是通过执行枢轴操作将行值移动到列上。

library(tidyr)

formatted_result <- sequenced_result %>%
  select(-c(situation, sequencing)) %>%
  pivot_wider(names_from = colname, values_from = Drugname)

print(formatted_result)

# A tibble: 4 x 7
  ID     DATE_RESULT    v1    v2 Drugname1            Drugname2              Neardrug1               
  <chr>  <chr>       <dbl> <dbl> <chr>                <chr>                  <chr>                   
1 111xxx 2007-11-28     NA   165 NA                   NA                     NA                      
2 111xxx 2009-07-08     NA   105 LAMISIL CREME 10MG/G TERBINAFINE TABL 250MG NA                      
3 222xxx 2009-08-24     NA   125 NA                   NA                     NA                      
4 222xxx 2012-03-27     66    20 NA                   NA                     MAGNESIUM HYD KAUWT 724~

作为画龙点睛的一笔,如果您愿意,您可以只显示每个药物名称的第一个单词。

library(stringr)

formatted_result_short <- sequenced_result %>%
  select(-c(situation, sequencing)) %>%
  mutate(Drugname = word(Drugname)) %>%
  pivot_wider(names_from = colname, values_from = Drugname)

print(formatted_result_short)
  ID     DATE_RESULT    v1    v2 Drugname1 Drugname2   Neardrug1
  <chr>  <chr>       <dbl> <dbl> <chr>     <chr>       <chr>    
1 111xxx 2007-11-28     NA   165 NA        NA          NA       
2 111xxx 2009-07-08     NA   105 LAMISIL   TERBINAFINE NA       
3 222xxx 2009-08-24     NA   125 NA        NA          NA       
4 222xxx 2012-03-27     66    20 NA        NA          MAGNESIUM

推荐阅读