1) Для каждой строки это находит интервал, содержащий тестовое значение с наибольшим начальным значением и одинаковым идентификатором, или, если его нет, он находит интервал с самым большим начальным значением, не превышающим тестовое значение с тем же идентификатором.
Сначала добавьте номер строки seq
в df1, создав временную таблицу df1s, а затем присоедините к каждой строке в df1s строку со строкой в df2, которая содержит тестовое значение и имеет тот же идентификатор и наибольшее значение. Кроме того, он создает временную таблицу df1b, которая находит наибольшее число перед тестовой датой и имеет тот же идентификатор. Наконец, он присоединяется к df1a и df1b в последующем, получая начальное значение, конечную дату и дозу от df1a, если они существуют, и от df2, если нет.
library(sqldf)
sqldf("with df1s as (
select rowid as seq, * from df1
),
df1a as ( -- nearest preceding containing interval having same ID
select max(b.begindate) as begindate, a.*, b.begindate, b.enddate, b.Dose
from df1s a
left join df2 b on a.ID = b.ID and a.testdate between b.begindate and b.enddate
group by a.seq),
df1b as ( -- nearest preceding begindate having same ID
select max(b.begindate), a.*, b.begindate, b.enddate, b.Dose
from df1s a
left join df2 b on a.ID = b.ID and b.begindate <= a.testdate
group by a.seq)
-- pick out interval in df1a or if none in df1b
select a.ID, a.testdate, a.testvalue,
coalesce(a.begindate, b.begindate) as begindate,
coalesce(a.enddate, b.enddate) as enddate,
coalesce(a.Dose, b.Dose) as Dose
from df1a a
left join df1b b on a.seq = b.seq")
, что дает следующее с использованием пересмотренных данных в вопросе:
ID testdate testvalue begindate enddate Dose
1 1 2010-03-20 17 <NA> <NA> <NA>
2 1 2018-04-12 35 2018-04-10 2018-04-22 2x per day
3 1 2018-04-25 44 2018-04-10 2018-04-22 2x per day
4 2 2011-04-17 65 2011-04-12 2011-04-30 1x morning
5 2 2011-09-05 21 2011-07-15 2011-07-30 2x morning
6 2 2019-04-16 22 2018-01-21 2018-01-29 3x per day
2) Если уменьшить (1) до df1b
, мы получим гораздо более короткое решение, хотя, очевидно, не эквивалентное. Он просто принимает самое большое значение в df2, которое не больше, чем testdate в df1 и имеет тот же идентификатор. Возможно, что он предпочтет совпадение, которое не охватывает тестовое значение, даже если есть интервал, который существует в случае, если есть интервал, содержащий тестовое значение, но другой интервал содержится в этом интервале и заканчивается перед тестовым значением; однако, кроме этого, все должно быть в порядке. Используйте (1), если это не так.
library(sqldf)
sqldf("select a.*, max(b.begindate) as begindate, b.enddate, b.Dose
from df1 a
left join df2 b on a.ID = b.ID and b.begindate <= a.testdate
group by a.rowid")
, используя следующие данные, используя пересмотренные данные в вопросе:
ID testdate testvalue begindate enddate Dose
1 1 2010-03-20 17 <NA> <NA> <NA>
2 1 2018-04-12 35 2018-04-10 2018-04-22 2x per day
3 1 2018-04-25 44 2018-04-10 2018-04-22 2x per day
4 2 2011-04-17 65 2011-04-12 2011-04-30 1x morning
5 2 2011-09-05 21 2011-07-15 2011-07-30 2x morning
6 2 2019-04-16 22 2018-01-21 2018-01-29 3x per day