现实生活中的问题:我有研究志愿者抽血的测试结果。我想将这些结果与志愿者的人口统计和调查数据合并,但是其中许多是在不同的日期(跨年)进行多次研究的。因此,调查数据行必须与测试结果的受试者ID完全匹配,并与采血日期尽可能接近(可能准确,也可能相隔几天或几周)。同样,一些受试者从不同的抽血日期获得多种血液测试结果。
玩具示例:
set.seed(905)
#The "test result" data frame:
df.1 <- tibble(id = c('A1', 'A1', 'A2', 'A3', 'A3'),
draw.date = as.Date(c("2013-01-19", "2015-03-22", "2013-01-19",
"2014-04-23", "2016-05-07")),
result1 = rnorm(5))
#The "survey results" data frame:
df.2 <- tibble(id = c('A1', 'A1', 'B1', 'A2', 'A3'),
test.date = as.Date(c("2013-02-01", "2015-02-28", "2017-01-26",
"2014-04-23", "2016-05-06")),
survey1 = 101:105,
survey2 = letters[1:5])
#The desired final data frame:
desired <- tibble(id = df.1$id,
draw.date = df.1$draw.date,
result1 = df.1$result1,
test.date = as.Date(c("2013-02-01", "2015-02-28", "2014-04-23",
"2016-05-06", "2016-05-06")),
survey1 = c(101, 102, 104, 105, 105),
survey2 = c('a', 'b', 'd', 'e', 'e'))
评论:
我在让R仅在具有匹配ID的用户中查找最接近的日期时遇到麻烦。换句话说,阻止它针对所有test.dates检查draw.date并将其限制为仅具有匹配ID的test.dates。
我已经搜索了先前的问题,但是在两个日期不同的数据帧(第二个匹配变量)中,没有一个具有重复的ID(主要匹配变量)。我找不到任何适合我的东西。
我更喜欢dplyr解决方案,但是对任何可行的方法都持开放态度。我对data.table包不熟悉,因此,如果这是我唯一的选择,请慢慢引导我:)
注意:我的现实生活中df.1是1524 obs x 22 vars,df.2是26802 obs x 7317 vars。
答案 0 :(得分:3)
可以使用滚动连接到“最近”来解决此问题,data.table
library(data.table) # version 1.11.4 used
setDT(df.2)[, draw.date := test.date][setDT(df.1), on = .(id, draw.date), roll = "nearest"]
id test.date survey1 survey2 draw.date result1 1: A1 2013-02-01 101 a 2013-01-19 2.9201353 2: A1 2015-02-28 102 b 2015-03-22 -0.3485295 3: A2 2014-04-23 104 d 2013-01-19 0.3824341 4: A3 2016-05-06 105 e 2014-04-23 0.3077772 5: A3 2016-05-06 105 e 2016-05-07 -0.8427319
为进行比较,这是OP的预期结果:
desired
id draw.date result1 test.date survey1 survey2 1: A1 2013-01-19 2.9201353 2013-02-01 101 a 2: A1 2015-03-22 -0.3485295 2015-02-28 102 b 3: A2 2013-01-19 0.3824341 2014-04-23 104 d 4: A3 2014-04-23 0.3077772 2016-05-06 105 e 5: A3 2016-05-07 -0.8427319 2016-05-06 105 e
答案 1 :(得分:2)
dplyr
方法可能是
library(dplyr)
df.1 %>%
left_join(df.2, by = "id") %>%
mutate(date_diff = abs(difftime(draw.date, test.date, units = "days"))) %>%
group_by(id, draw.date) %>%
filter(date_diff == min(date_diff)) %>%
select(-date_diff)
给出
id draw.date result1 test.date survey1 survey2
1 A1 2013-01-19 2.92 2013-02-01 101 a
2 A1 2015-03-22 -0.349 2015-02-28 102 b
3 A2 2013-01-19 0.382 2014-04-23 104 d
4 A3 2014-04-23 0.308 2016-05-06 105 e
5 A3 2016-05-07 -0.843 2016-05-06 105 e