Наиболее эффективный способ условного объединения двух таблиц data.tables при применении функции

#r #merge #data.table #cartesian-product #processing-efficiency

Вопрос:

У меня есть большие данные.таблица cohort_D0_multvis изменяющихся во времени дат встреч (т. Е. CONTACT_DATE ), и я хочу объединить эти данные.таблица с несколькими наборами лабораторных данных, также большими данными.таблица; для каждого CONTACT_DATE я хочу сохранить лабораторное измерение, которое происходит ближе всего, но строго ниже, чем дата встречи. Я также хочу сохранить любые записи без каких-либо лабораторных данных или записей, которые не соответствовали логике вышеупомянутого предложения.

Мне удалось объединить данные.таблицу дат встреч , изменяющихся во времени cohort_D0_multvis , с данными.таблицей лабораторных данных A1c во время кондиционирования CONTACT_DATE>LAB_DATE , как показано ниже:

Условное слияние:

 test <- cohort_D0_multvis[unique(A1c)
                          , on = .(ID, CONTACT_DATE > LAB_DATE)
                          , nomatch = 0
                          , .(ID, CONTACT_DATE = x.CONTACT_DATE, LAB_DATE, A1c)]
 

Затем я создал новый столбец test[,date_diff:=as.numeric(CONTACT_DATE-LAB_DATE) , а затем использовал .SD[which.min(date_diff)] его для сохранения лабораторных измерений, которые происходят ближе всего к дате встречи. Наконец, я объединил эти оставшиеся записи обратно в свои данные о встречах, чтобы включить любые записи, которые могли быть удалены из-за логики создания условий выше, как показано ниже:

Промежуточные этапы:

 test[,date_diff:=as.numeric(CONTACT_DATE-LAB_DATE)]
test <- test[,.SD[which.min(date_diff)],by=.(ID,CONTACT_DATE)]
test <- merge(test,cohort_D0_multvis,by=c("ID","CONTACT_DATE"),all.y = TRUE)
 

Окончательный набор данных:

 ### This is exactly what I want
   ID CONTACT_DATE   LAB_DATE      A1c date_diff
 1:  A   2002-01-26 2000-09-30 4.938065       483
 2:  A   2004-10-26 2000-09-30 4.938065      1487
 3:  A   2006-09-01 2000-09-30 4.938065      2162
 4:  A   2014-05-23 2007-12-08 6.170197      2358
 5:  A   2017-01-28 2007-12-08 6.170197      3339
 6:  A   2020-04-16 2007-12-08 6.170197      4513
 7:  B   1998-03-02       <NA>       NA        NA
 8:  B   2003-05-08       <NA>       NA        NA
 9:  B   2004-09-27 2003-10-14 7.071354       349
10:  B   2008-11-05 2007-06-04 5.173654       520
11:  B   2015-11-24 2014-06-03 6.100639       539
12:  C   1993-08-30       <NA>       NA        NA
13:  C   1993-10-04       <NA>       NA        NA
14:  C   1996-07-01 1995-07-28 5.852059       339
15:  C   1996-11-08 1995-07-28 5.852059       469
16:  C   1999-02-19 1995-07-28 5.852059      1302
17:  C   2012-01-03 2005-03-16 6.640102      2484
18:  C   2020-05-17 2018-11-23 4.729267       541
 

Однако фактические данные о встречах и лабораторные данные, с которыми я работаю, содержат более 1,3 миллиона записей, и приведенное выше условное объединение приведет к выходу с дублированными уникальными встречами, каждая уникальная лабораторная запись по идентификатору (т. Е. Более nrow(x) nrow(i) строк). Мне придется повторить этот процесс около 10 раз (т. Е. Объединить около 10 наборов лабораторных данных с набором данных о встрече), что потребует очень много времени и памяти.

Мой вопрос:

  • Существует ли более эффективный способ получить мой окончательный набор данных без необходимости создавать набор данных с более чем nrow(x) nrow(i) строк при выполнении условного слияния?

Мы будем очень признательны за любой совет или помощь. Ниже приведен код для воспроизведения моего вывода.

Reproducible Example:

 library(data.table)
library(lubridate)

### Create sample cohort with screening dates
set.seed(1992)
cohort_D0_multvis <- data.table(ID=c(rep("A",6),rep("B",5),rep("C",7)),
                                CONTACT_DATE=c(sample(seq(as_date('1992/01/01'), as_date('2021/06/04'), by="day"), 6),
                                               sample(seq(as_date('1992/01/01'), as_date('2021/06/04'), by="day"), 5),
                                               sample(seq(as_date('1992/01/01'), as_date('2021/06/04'), by="day"), 7)))

setkeyv(cohort_D0_multvis,c("ID","CONTACT_DATE"))
cohort_D0_multvis

### Create sample a1c data with lab dates
set.seed(304)
A1c <- data.table(ID=c(rep("A",6),rep("B",5),rep("C",7)),
                  LAB_DATE=c(sample(seq(as_date('1992/01/01'), as_date('2021/06/04'), by="day"), 6),
                             sample(seq(as_date('1992/01/01'), as_date('2021/06/04'), by="day"), 5),
                             sample(seq(as_date('1992/01/01'), as_date('2021/06/04'), by="day"), 7)),
                  A1c=rnorm(18,5.7,1))
setkeyv(A1c,c("ID","LAB_DATE"))
A1c

### For every CONTACT_DATE we want to retain the lab measurement that occurs closest to, but strictly lower, than the screening date
test <- cohort_D0_multvis[unique(A1c)
                          , on = .(ID, CONTACT_DATE > LAB_DATE)
                          , nomatch = 0
                          , .(ID, CONTACT_DATE = x.CONTACT_DATE, LAB_DATE, A1c)]

test[,date_diff:=as.numeric(CONTACT_DATE-LAB_DATE)]
test <- test[,.SD[which.min(date_diff)],by=.(ID,CONTACT_DATE)]
# Bring back patients w/o lab data
test <- merge(test,cohort_D0_multvis,by=c("ID","CONTACT_DATE"),all.y = TRUE)
test