Р: Нахождение ближайшей из двух дат по столбцу индекса - PullRequest
2 голосов
/ 16 октября 2019

Целью этого проекта является измерение временного интервала между проверкой в ​​медицинской лаборатории и самой последней дозой лекарства. У каждого пациента разное количество последующих доз этого лекарства, и количество последующих лабораторных проверок также различно для каждого субъекта.

Первый фрейм данных содержит study_id и даты соответствующих доз:

library(dplyr)
library(lubridate)

study_id<- c(1, 1, 1, 2, 2, 3)
dose_dt <- c('1/1/00', '2/1/00', '3/1/00', '1/1/01', '2/1/01', '1/1/02')
doses_df <- data.frame(study_id, dose_dt)
doses_df$dose_dt <- mdy(doses_df$dose_dt)
print(doses_df)

 study_id    dose_dt
1        1 2000-01-01
2        1 2000-02-01
3        1 2000-03-01
4        2 2001-01-01
5        2 2001-02-01
6        3 2002-01-01

Второй фрейм данных имеет совпадающий study_id, на этот раз с датами лабораторных проверок и соответствующими лабораторными значениями, а также индикатором аномалий (да нет).

study_id <- c(1, 1, 1, 2, 3, 3, 3)
lab_dt <- c('1/1/99', '3/1/00', '4/1/00', '2/1/01', '2/1/02', '3/1/02', '4/1/02')
lab_result <- c(100, 200, 50, 25, 75, 100, 75)
lab_abn_yn <- c(0, 0, 1, 1, 1, 0, 1)
labs_df <- data.frame(study_id, lab_dt, lab_result, lab_abn_yn)
labs_df$lab_dt <- mdy(labs_df$lab_dt)
print(labs_df)

  study_id     lab_dt lab_result lab_abn_yn
1        1 1999-01-01        100          0
2        1 2000-03-01        200          0
3        1 2000-04-01         50          1
4        2 2001-02-01         25          1
5        3 2002-02-01         75          1
6        3 2002-03-01        100          0
7        3 2002-04-01         75          1

Обратите внимание, что у субъекта 1 есть один лабораторный осмотр, который был в прошлом до первой дозы лекарства, у субъекта 2 больше доз, чем лабораторных, а у субъекта 3 меньше доз, чем лабораторных.

Я хочу, чтобы R определил дату самой последней дозы лекарства до лабораторной проверки, чтобы я мог рассчитать интервал между дозой и лабораторной проверкой. Выход будет сохранять лабораторные значения и показатели. Предпочтительно, чтобы лабораторные проверки до первой дозы (отрицательный интервал времени от дозы до лабораторной проверки) регистрировались как NA, но я легко могу отфильтровать отрицательные временные интервалы. Я также знаю, как использовать lubridate для расчета временных интервалов, поэтому нужно добавить это к объяснению.

Желаемый вывод:

  study_id lab_dt     most_recent_dose_dt lab_result lab_abn_yn interval_months
     <dbl> <chr>      <chr>               <chr>           <dbl>           <dbl>
1        1 1999-01-01 NA                  NA                 NA          NA    
2        1 2000-03-01 2000-02-02          200                 0           0.966
3        1 2000-04-01 2000-03-01          50                  1           1    
4        2 2001-02-01 2001-01-01          25                  1           1    
5        3 2002-02-01 2002-01-01          75                  1           1    
6        3 2002-03-01 2002-01-01          100                 0           2    
7        3 2002-04-01 2002-01-01          75                  1           3      

Я пробовал несколько схем слияния, но ни одна не сохраняет все данные. Есть ~ 40 000 предметов, поэтому сделать это вручную невозможно. Любая помощь высоко ценится.

Ответы [ 2 ]

2 голосов
/ 17 октября 2019

Существует однострочное решение с data.table, использующее non-equi объединений:

library(data.table)
# create data.tables
labs_df <-  setDT(labs_df)
doses_df <- setDT(doses_df)

# create join variable
doses_df[,join_time := dose_dt]
labs_df[,join_time := lab_dt]

# do nonequi join with a condition
doses_df[labs_df,on=.(study_id,join_time < join_time),mult = "last"]

   study_id    dose_dt  join_time     lab_dt lab_result lab_abn_yn
1:        1       <NA> 1999-01-01 1999-01-01        100          0
2:        1 2000-02-01 2000-03-01 2000-03-01        200          0
3:        1 2000-03-01 2000-04-01 2000-04-01         50          1
4:        2 2001-01-01 2001-02-01 2001-02-01         25          1
5:        3 2002-01-01 2002-02-01 2002-02-01         75          1
6:        3 2002-01-01 2002-03-01 2002-03-01        100          0
7:        3 2002-01-01 2002-04-01 2002-04-01         75          1

Здесь идея состоит в том, что вы объединяете дозы_df в study_id и join_time из labs_df которые соблюдают условие join_time из доза_дф <<1010 * из labs_df. </p>

Я создаю столбец join_time, потому что объединение сохраняет только один из двух столбцов времени в противном случае и меняет имена, поэтому явсегда запутайтесь: если вы делаете прямо

doses_df[labs_df,on=.(study_id,dose_dt < lab_dt),mult = "last"]

Это дает вам

   study_id    dose_dt lab_result lab_abn_yn
1:        1 1999-01-01        100          0
2:        1 2000-03-01        200          0
3:        1 2000-04-01         50          1
4:        2 2001-02-01         25          1
5:        3 2002-02-01         75          1
6:        3 2002-03-01        100          0
7:        3 2002-04-01         75          1

, который подходит для lab_result и других столбцов, но сбивает с толку для столбца dose_dt, потому чтоон становится столбцом lab_dt, с которым вы произвели слияние (слияние похоже на подстановку столбца doses_dt для значений lab_dt).

Я действительно хотел использовать прокручивающиеся объединения в начале:

doses_df[labs_df,on=.(study_id,join_time),roll = T]

   study_id    dose_dt  join_time     lab_dt lab_result lab_abn_yn
1:        1       <NA> 1999-01-01 1999-01-01        100          0
2:        1 2000-03-01 2000-03-01 2000-03-01        200          0
3:        1 2000-03-01 2000-04-01 2000-04-01         50          1
4:        2 2001-02-01 2001-02-01 2001-02-01         25          1
5:        3 2002-01-01 2002-02-01 2002-02-01         75          1
6:        3 2002-01-01 2002-03-01 2002-03-01        100          0
7:        3 2002-01-01 2002-04-01 2002-04-01         75          1

но проблема в том, что она сохраняет дату равной или меньшей.

Я использовал этот вопрос , чтобы найти решение равных объединений, и я рекомендую этот урок для подвижных объединений. data.table быстрый и позволяет вам в одну строку делать то, что вы на самом деле хотите (взять последнюю строку в слиянии, соответствующую dose_dt < lab_dt).

1 голос
/ 17 октября 2019

Мы можем сделать это в три шага:

  1. Фильтр, чтобы сохранить только дозы, которые произошли после лабораторной даты
  2. Фильтр, чтобы сохранить только дозу, которая была самой последней для каждоголабораторная дата (которая теперь является самой последней дозой благодаря первому фильтру)
  3. Присоединитесь к списку лабораторий, чтобы повторно включить лабораторные даты, у которых не было предыдущих доз

Примечаниечто ваши данные выборки не совсем так, как напечатано в желаемом, в том, что 1 февраля стал 2 февраля для второго наблюдения.

library(tidyverse)
library(lubridate)
doses_df <- tibble(
  study_id = c(1, 1, 1, 2, 2, 3),
  dose_dt = mdy(c("1/1/00", "2/1/00", "3/1/00", "1/1/01", "2/1/01", "1/1/02"))
)
labs_df <- tibble(
  study_id = c(1, 1, 1, 2, 3, 3, 3),
  lab_dt = mdy(c("1/1/99", "3/1/00", "4/1/00", "2/1/01", "2/1/02", "3/1/02", "4/1/02")),
  lab_result = c(100, 200, 50, 25, 75, 100, 75),
  lab_abn_yn = c(0, 0, 1, 1, 1, 0, 1)
)

most_recent_doses <- labs_df %>%
  left_join(doses_df, by = "study_id") %>%
  group_by(study_id, lab_dt) %>%
  filter(dose_dt < lab_dt) %>%
  filter(dose_dt == max(dose_dt)) %>%
  select(study_id, lab_dt, dose_dt)

labs_df %>%
  left_join(most_recent_doses, by = c("study_id", "lab_dt")) %>%
  mutate(interval_months = interval(dose_dt, lab_dt) / months(1))
#> # A tibble: 7 x 6
#>   study_id lab_dt     lab_result lab_abn_yn dose_dt    interval_months
#>      <dbl> <date>          <dbl>      <dbl> <date>               <dbl>
#> 1        1 1999-01-01        100          0 NA                      NA
#> 2        1 2000-03-01        200          0 2000-02-01               1
#> 3        1 2000-04-01         50          1 2000-03-01               1
#> 4        2 2001-02-01         25          1 2001-01-01               1
#> 5        3 2002-02-01         75          1 2002-01-01               1
#> 6        3 2002-03-01        100          0 2002-01-01               2
#> 7        3 2002-04-01         75          1 2002-01-01               3

Создано в 2019-10-16 представьте пакет (v0.3.0)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...