R: Использование значений из кадра данных A с даты, предшествующей заполнению строки в кадре данных B

Это может быть очень сложно, и я подозреваю, что это требует передовых знаний. У меня есть два разных типа данных. Я должен комбинировать:

Данные:

Dataframe A:

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

Patient ID Transfusion.Date
1          01/01/2000
1          01/30/2000
2          04/01/2003
3          04/01/2003

Кадры данных типа B содержат результаты тестов в другие даты, а также идентификатор пациента:

Patient ID  Test.Date   Test.Value
1           11/30/1999   negative
1           01/15/2000   700 copies/uL
1           01/27/2000   900 copies/uL
2           03/30/2003   negative

Я хотел бы иметь Dataframe A с таким же количеством строк (1 для каждой переливания) и с самым последним Test.Value в качестве отдельного столбца. Каждая дата трансфузии должна иметь результат теста теста, проведенного наиболее близко (ранее) до переливания.

желаемый результат:

- >

Patient ID Transfusion.Date Pre.Transfusion.Test
1          01/01/2000       negative
1          01/30/2000       900 copies/ul
2          04/01/2003       negative
3          04/01/2003       NA

Я думаю, что общая стратегия заключалась бы в подмножестве data.frames по идентификаторам пациентов. Затем возьмите все даты переливания для пациента 1, проверьте, какой результат ближе всего к всем доступным значениям test_dates для каждого элемента, а затем верните ближайшее значение.

Как я могу объяснить R для этого?

Изменить 1. Здесь приведен код R для этих примеров.

df_A <- data.frame(MRN = c(1,1,2,3), 
                   Transfusion.Date = as.Date(c('01/01/2000', '01/30/2000', 
                   '04/01/2003','04/01/2003'),'%m/%d/%Y')) 

df_B <- data.frame(MRN = c(1,1,1,2), 
                   Test.Date = as.Date(c('11/30/1999', '01/15/2000', '01/27/2000', 
                   '03/30/2003'),'%m/%d/%Y'), Test.Result = c('negative', 
                   '700 copies/ul','900 copies/ul','negative'))

Изменить 2:

Чтобы уточнить, результирующие данные должны быть: пациент А получил переливание в день X и день Y. (для df_A). До переливания в день X его последний результат теста был Х (ближайшая дата теста для первого переливания в df_B). До переливания в день Y его последний результат теста был Y (до второго переливания, также в df_B. Df_B также содержит кучу других дат тестирования, которые не нужны для конечного результата.

Ответ 1

Здесь с использованием data.table катящихся соединений:

require(data.table)
setkey(setDT(df_A), MRN, Transfusion.Date)
setkey(setDT(df_B), MRN, Test.Date)

df_B[df_A, roll=TRUE]
#    MRN  Test.Date   Test.Result
# 1:   1 2000-01-01      negative
# 2:   1 2000-01-30 900 copies/ul
# 3:   2 2003-04-01      negative
# 4:   3 2003-04-01            NA
  • setDT преобразует data.frame в data.table по ссылке (без какого-либо дополнительного копирования). Это приведет к тому, что df_A и df_B теперь будут data.tables.

  • setkey сортирует data.table по столбцам, которые мы предоставили, и маркирует эти столбцы в качестве ключевых столбцов, что позволяет нам использовать объединения на основе бинарного поиска.

  • Мы выполняем объединение формы x[i] в ключевых столбцах, где для каждой строки i сопоставляемые строки x (если есть, еще NA) вместе с i строками возвращаются. Это то, что мы называем equi-join. Добавляя roll = TRUE, в случае несоответствия последнее наблюдение переносится вперед (LOCF). Это то, что мы называем скользящим соединением. Сортировка в порядке возрастания (из-за setkey()) гарантирует, что последнее наблюдение является самой последней датой.

НТН

Ответ 2

 dfLast <- df_B[ df_B$Test.Date %in% 
  as.Date( tapply(df_B$Test.Date, df_B$MRN, tail,1),"1970-01-01"), ]
 merge(df_A, dfLast, by=c(1:2,1:2) ,all.y=TRUE)
  MRN Transfusion.Date   Test.Result
1   1       2000-01-27 900 copies/ul
2   2       2003-03-30      negative

Под ред. Были некоторые логические ошибки и некоторые ситактивные ошибки. tapply вернули целые значения дат и, как вы указали, я использовал неправильное имя столбца на шаге сокращения данных.

Ответ 3

ОК спасибо за помощь. Мне потребовалось много труда, крови, потом и слез, но это решение, с которым я столкнулся:

  • Объединить оба фрейма данных:

df_AB <-merge (df_A, df_B, all.x = T)

df_AB:

  MRN Transfusion.Date  Test.Date   Test.Result
1   1       2000-01-01 1999-11-30      negative
2   1       2000-01-01 2000-01-15 700 copies/ul
3   1       2000-01-01 2000-01-27 900 copies/ul
4   1       2000-01-30 1999-11-30      negative
5   1       2000-01-30 2000-01-15 700 copies/ul
6   1       2000-01-30 2000-01-27 900 copies/ul
7   2       2003-04-01 2003-03-30      negative
8   3       2003-04-01       <NA>          <NA>

Используя dplyr

df_tests <- df_AB %>% 
  group_by(MRN, Transfusion.Date) %>%
  mutate(Time.Difference = Transfusion.Date - Test.Date) %>%
  filter(Time.Difference > 0) %>%
  arrange(Time.Difference) %>%
  summarize(Test.Date = Test.Date[1], Test.Result = Test.Result[1])

df_tests:

  MRN Transfusion.Date  Test.Date Test.Result
1   1       2000-01-01 1999-11-30    negative
2   1       2000-01-30 1999-11-30    negative
3   2       2003-04-01 2003-03-30    negative

using merge again for MRN3:

df_desired <- merge(df_A, df_tests, all.x = T)

  MRN Transfusion.Date  Test.Date   Test.Result
1   1       2000-01-01 1999-11-30      negative
2   1       2000-01-30 2000-01-27 900 copies/ul
3   2       2003-04-01 2003-03-30      negative
4   3       2003-04-01       <NA>          <NA>