如何解决在日期范围内有效地连接 R或 SQL 表中的两个 data.tables?
我正在使用入院数据,并试图将观察表联系在一起:
dt_taken | 患者 ID | 观察 | 价值 |
---|---|---|---|
2020-04-13 00:00:00 | 患者01 | “心率” | 69 |
... |
... 附上一张录取名单:
患者 ID | admission_id | 开始日期 | 结束日期 |
---|---|---|---|
患者01 | admission01 | 2020-04-01 00:04:20 | 2020-05-01 00:23:59 |
... |
...这样它会返回与入院相关的观察列表,并拒绝所有在入院期间未进行的观察(错误记录,或在门诊就诊等):
dt_taken | admission_id | 观察 | 价值 |
---|---|---|---|
2020-04-13 00:00:00 | admission01 | “心率” | 69 |
... |
我迄今为止相对简单的方法是迭代每个患者,然后每个患者的入院,然后每个观察并将其分配给该入院,但鉴于我有 > 36k 入院和 > 100 万个观察,这非常耗时(我的政府发行的笔记本电脑因此讨厌我)。
有没有更有效的方法,我想念的,要么使用 {data.table}(我必须承认我是这里的绝对新手,更喜欢在 {tidyverse} 中工作),或者甚至我可以在 sql 上运行存储表以保存我老化的笔记本电脑的服务器?
解决方法
数据表
对于 data.table
,这主要是对 How to perform join over date ranges using data.table? 的欺骗,尽管它没有提供 RHS[LHS,on=.(..)]
方法。
observations
# dt_taken patient_id observation value
# 1 2020-04-13 00:00:00 patient01 Heart rate 69
admissions
# patient_id admission_id startdate enddate
# 1 patient01 admission01 2020-04-01 00:04:20 2020-05-01 00:23:59
### convert to data.table
setDT(observations)
setDT(admissions)
### we need proper 'POSIXt' objects
observations[,dt_taken := as.POSIXct(dt_taken)]
admissions[,(dates) := lapply(.SD,as.POSIXct),.SDcols = dates]
还有加入。
admissions[observations,on = .(patient_id,startdate <= dt_taken,enddate >= dt_taken)]
# patient_id admission_id startdate enddate observation value
# <char> <char> <POSc> <POSc> <char> <int>
# 1: patient01 admission01 2020-04-13 2020-04-13 Heart rate 69
我认为有两点值得注意:
-
在 SQL(以及其他对连接友好的语言中类似),它通常显示为
select ... from TABLE1 left join TABLE2 ...
建议
TABLE1
是 LHS(左侧),TABLE2
是 RHS 表。 (这是一个粗略的概括,主要面向左连接,因为这就是data.table::[
支持的全部内容;对于内部/外部/完全连接,您需要merge(.)
或其他外部机制。请参阅 {{ 3}} 和 How to join (merge) data frames (inner,outer,left,right) 以了解有关 JOIN 等的更多讨论)由此,
data.table::[
的机制是有效的TABLE2[TABLE1,on = .(...)] RHS[LHS,on = .(...)]
(意思是右边的表实际上是从左到右的第一个表...)
-
inequi-joins 输出中的名称从 RHS 中保留,请参阅未找到
dt_taken
。 但是,这些startdate
和enddate
列的值来自dt_taken
。因此,我经常找到最简单的方法来让我的大脑围绕重命名和值,例如当我不确定时,我将一个连接列复制到一个新列中并使用该列连接,然后在合并后将其删除。这是草率和懒惰,但我发现自己错过了太多次并认为这不是我所想的。
sqldf
如果 SQL 看起来更直观,这可能会更直接一些。
sqldf::sqldf(
"select ob.*,ad.admission_id
from observations ob
left join admissions ad on ob.patient_id=ad.patient_id
and ob.dt_taken between ad.startdate and ad.enddate")
# dt_taken patient_id observation value admission_id
# 1 2020-04-13 patient01 Heart rate 69 admission01
数据(已经 data.table
和 POSIXt
,与 sqldf
一样好用,不过普通的 data.frame
也能正常工作):
admissions <- setDT(structure(list(patient_id = "patient01",admission_id = "admission01",startdate = structure(1585713860,class = c("POSIXct","POSIXt" ),tzone = ""),enddate = structure(1588307039,"POSIXt"),tzone = "")),class = c("data.table","data.frame"),row.names = c(NA,-1L)))
observations <- setDT(structure(list(dt_taken = structure(1586750400,patient_id = "patient01",observation = "Heart rate",value = 69L),-1L)))
(我使用 setDT
来修复我们无法在此处传递 .internal.selfref
属性的事实。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。