Как объединить даты - PullRequest
       1

Как объединить даты

1 голос
/ 07 марта 2020

У меня есть 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. 

Я хотел бы объединить df1 и df2, чтобы они выглядели так:

       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_RESULT в df2 находится между Startdate и Enddate в df1. Поскольку ID s может иметь несколько Drugname s, я бы хотел, чтобы они были объединены в одном ряду друг за другом, как видно во втором ряду нового df.

Тогда я бы хотел еще одно слияние / столбец (и я не знаю, возможно ли это), я бы хотел слить на ID только тогда, когда DATE_RESULT в df2 наступит максимум через 7 дней после Enddate в df1, создание столбца Neardrug, как видно в строке 4 нового df.

Для первого выпуска я пробовал это: r объединить по идентификатору и дате между двумя датами , но это не совсем дает мне желаемый новый фрейм данных, и я слишком новичок, чтобы изменить этот код.

Я хотел бы сохранить все данные в df2, а не df1. Вся информация была изменена по понятным причинам.

Ответы [ 2 ]

1 голос
/ 07 марта 2020

Хорошо тогда! Давайте разделим вашу проблему на две части. Первая часть состоит в том, чтобы выполнить указанное объединение по дате, а вторая часть имеет множество результатов, распределенных по столбцам, а не по строкам.

Часть 1 Хотя data.table может помочь, советую в пользу использования sqldf, который позволяет вам использовать синтаксис 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».

Part 2 Теперь вы хотите распространить результаты много строк для одного и того же идентификатора, чтобы стать столбцами. Идеальный формат - хранить их как есть, в кадре данных строк и столбцов, без повторяющихся столбцов. Это называется форматом tidy, и это то, что обычно используется несколькими библиотеками R в качестве стандарта, что имеет несколько преимуществ.

Таким образом, мы можем рассматривать формат в виде столбца как форматирование для распечатки, чтобы сделать это более читабельно. Есть и другие проблемы. Если у вас слишком много столбцов, а их содержимое слишком длинное, управление может оказаться затруднительным. Но давайте сделаем это.

Чтобы сделать это, нам сначала нужно создать имена последовательности для ситуаций 'Drugname' в 'Drugname1', 'Drugname2', et c. То же самое для 'Neardrug' -> 'Neardrug1', 'Neardrug2', et c.

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

Мы почти у цели. Теперь все, что нам нужно сделать, это переместить значения строк в столбцы, выполнив операцию pivot .

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
0 голосов
/ 08 марта 2020

Если я правильно понимаю, ОП хочет идентифицировать

  1. все лекарства, которые были назначены человеку ID на дату проведения медицинского анализа DATE_RESULT и
  2. все лекарства, которые были приняты в течение последних семи дней до , был проведен медицинский анализ.

Итак, нам нужно найти перекрывающиеся диапазоны дат. Это может быть реализовано путем агрегирования в неэквивалентном объединении с использованием пакета data.table:

library(data.table)
setDT(df1)
setDT(df2)
condense <- function(x) toString(unique(stringr::str_extract(x, "^\\w+")))
df2[, c("Drugname", "Neardrugs") := .(
  df1[df2, on = .(ID, Startdate <= DATE_RESULT, Enddate >= DATE_RESULT), 
      condense(Drugname), by = .EACHI]$V1, 
  df1[df2[, .(ID, DATE_RESULT, DRm7 = DATE_RESULT - 7L)], 
      on = .(ID, Enddate <= DATE_RESULT, Enddate >= DRm7), 
      condense(Drugname), by = .EACHI]$V1)][]
       ID DATE_RESULT v1  v2             Drugname Neardrugs
1: 111xxx  2007-11-28 NA 165                   NA        NA
2: 111xxx  2009-07-08 NA 105 LAMISIL, TERBINAFINE        NA
3: 222xxx  2009-08-24 NA 125                   NA        NA
4: 222xxx  2012-03-27 66  20                   NA MAGNESIUM

Объяснение

Выражение

df1[df2, on = .(ID, Startdate <= DATE_RESULT, Enddate >= DATE_RESULT), 
    condense(Drugname), by = .EACHI]

вправо объединяет df1 и df2 при сопоставлении ID и проверяет, что DATE_RESULT находится в диапазоне дат [Startdate, Enddate] (закрытые интервалы). Параметр by = .EACHI запрашивает, чтобы данные были сгруппированы и агрегированы для каждого совпадения. Функция агрегирования - condense(), которая выбирает первое слово из каждого Drugname, отбрасывает дублирующиеся записи и объединяет записи в одну строку символов.

В результате получается

       ID  Startdate    Enddate                   V1
1: 111xxx 2007-11-28 2007-11-28                   NA
2: 111xxx 2009-07-08 2009-07-08 LAMISIL, TERBINAFINE
3: 222xxx 2009-08-24 2009-08-24                   NA
4: 222xxx 2012-03-27 2012-03-27                   NA

, из которого столбец результата V1 добавляется к df2 как новый столбец Drugname.

Выражение

df1[df2[, .(ID, DATE_RESULT, DRm7 = DATE_RESULT - 7L)], 
    on = .(ID, Enddate <= DATE_RESULT, Enddate >= DRm7), 
    condense(Drugname), by = .EACHI]

по существу такое же, но оно проверяет, что Enddate находится в диапазоне дат [DATE_RESULT - 7L, DATE_RESULT]. Поскольку мы не можем создать новый столбец «на лету» в предложении on = (который является длительным запросом функции , кстати), мы должны создать вспомогательный столбец DRm7 для присоединения.

Результат -

       ID    Enddate    Enddate        V1
1: 111xxx 2007-11-28 2007-11-21        NA
2: 111xxx 2009-07-08 2009-07-01        NA
3: 222xxx 2009-08-24 2009-08-17        NA
4: 222xxx 2012-03-27 2012-03-20 MAGNESIUM

, из которого столбец результатов V1 добавляется к df2 как новый столбец Neardrugs.

Данные

df1 <- readr::read_table("
i       ID  Drugname                    Startdate   Enddate     Dose   
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  ",
                         col_types = "_ccDDc")

df2 <- readr::read_table("
i    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     ",
                         col_types = "_cDii")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...