使用数据框A中的日期之前的值来填充数据框B中的一行

4

这可能非常复杂,我怀疑需要高级知识。现在我有两种不同类型的数据框需要合并:

数据:

数据框A:

按患者ID列出所有输血日期。每次输血都由单独的行表示,患者可以有多次输血。不同的患者可以在同一天接受输血。

Patient ID Transfusion.Date
1          01/01/2000
1          01/30/2000
2          04/01/2003
3          04/01/2003

类型B的数据帧包含同一病人ID的其他日期的测试结果:

Patient ID  Test.Date   Test.Value
1           11/30/1999   negative
1           01/15/2000   700 copies/uL
1           01/27/2000   900 copies/uL
2           03/30/2003   negative

我希望得到的是一个与Dataframe A行数相同的Dataframe,每个输血对应一行,并且最近的Test.Value应该作为单独的一列呈现。每次输血日期应该显示在其最近测试结果之前。
期望输出:
-->
Patient ID Transfusion.Date Pre.Transfusion.Test
1          01/01/2000       negative
1          01/30/2000       900 copies/ul
2          04/01/2003       negative
3          04/01/2003       NA

我认为一般策略是按病人ID子集化数据框。然后获取病人1的所有输血日期,对于每个元素,检查哪个结果最接近所有可用测试日期,然后返回最接近的值。
如何解释R来执行这个操作?
编辑1:这里是这些示例的R代码
df_A <- data.frame(MRN = c(1,1,2,3), 
                   Transfusion.Date = as.Date(c('01/01/2000', '01/30/2000', 
                   '04/01/2003','04/01/2003'),'%m/%d/%Y')) 

df_B <- data.frame(MRN = c(1,1,1,2), 
                   Test.Date = as.Date(c('11/30/1999', '01/15/2000', '01/27/2000', 
                   '03/30/2003'),'%m/%d/%Y'), Test.Result = c('negative', 
                   '700 copies/ul','900 copies/ul','negative'))

编辑2:

为了澄清,最终数据应该是:病人A在X日和Y日接受了输血(对于df_A)。在第一次输血前,他最近的检测结果为X(df_B中最接近第一次输血的检测日期)。在第二次输血之前,他最近的检测结果为Y(也在df_B中,在第二次输血之前)。df_B还包含一堆其他的测试日期,这些对最终结果不需要。


1
这应该可以让你开始使用 merge(df_A, df_B, by.x = "Patient.ID", by.y = "Patient.ID", all.x = TRUE),然后尝试使用 lubridate 包添加日期差异列。 - JasonAizkalns
@jaysunice3401 谢谢你的回答,我现在的情况是这样的,但是这种方法会为所有测试结果比输血次数多的时间产生大量额外的行。我认为我需要做的是使用你告诉我的包将 df_B 减少到相同数量的患者 ID 行,我正在研究这个问题! - col. slade
2
还可以查看 dplyr,通过 summarise() 轻松进行 group_by() 汇总 -- 按照患者ID和日期的组合进行分组,然后获取对应最小距离的记录。 - JasonAizkalns
@jaysunice3401,你能再帮我一下吗?我不知道该如何将这个与BondedDust的代码结合起来(?似乎不需要lubridate?)以得出一个可行的解决方案。 - col. slade
@jaysunice3401 谢谢你提到dplyr,正如你建议的那样,我使用了merge:df_AB <- merge(df_A, df_B, by.x = "Patient.ID", by.y = "Patient.ID", all.x = TRUE) df_AB %>% mutate(Date.difference = Test.Date - Transfusion.Date) 给我所有的日期差异,这非常有帮助。现在尝试筛选出所有最小负日期差异的行。 - col. slade
3个回答

6
这里使用`data.table`的滚动连接(rolling joins):
require(data.table)
setkey(setDT(df_A), MRN, Transfusion.Date)
setkey(setDT(df_B), MRN, Test.Date)

df_B[df_A, roll=TRUE]
#    MRN  Test.Date   Test.Result
# 1:   1 2000-01-01      negative
# 2:   1 2000-01-30 900 copies/ul
# 3:   2 2003-04-01      negative
# 4:   3 2003-04-01            NA
  • setDT通过引用将data.frame转换为data.table(无需任何额外的复制)。这将导致df_Adf_B现在成为了data.tables。

  • setkey按我们提供的列对data.table进行排序,并将这些列标记为关键列,这样就可以使用基于二进制搜索的联接。

  • 我们执行形式为x[i]的联接,其中对于每行,返回与x匹配的行(如果有,否则为NA)以及的行。这就是我们所谓的等值联接。通过添加roll = TRUE,在出现不匹配的情况下,将向前传递最后一个观察值(LOCF)。这就是我们所说的滚动联接。升序排序(由于setkey())确保最后一个观察值是最近的日期。

希望对您有所帮助。


哇,谢谢你。看来我真的需要研究一下 data.table,它非常简洁,滚动连接/LOCF 功能看起来很棒。特别感谢你对代码中 data.table 的解释。有没有办法为滚动功能指定“边界”,例如只在测试日期或输血前不超过 10 天时进行滚动连接?再次感谢! - col. slade
1
谢谢,很高兴知道。是的,roll = TRUE 相当于 roll=Inf - LOCF。你也可以设置 roll = 10 或 -10。roll = -Inf 表示 NOCB - 向后传递下一个观测值。roll = "nearest" 会滚动到最接近的值。请参考 ?data.table 和示例。我们还正在 创建详细的教程 - Arun

0
 dfLast <- df_B[ df_B$Test.Date %in% 
  as.Date( tapply(df_B$Test.Date, df_B$MRN, tail,1),"1970-01-01"), ]
 merge(df_A, dfLast, by=c(1:2,1:2) ,all.y=TRUE)
  MRN Transfusion.Date   Test.Result
1   1       2000-01-27 900 copies/ul
2   2       2003-03-30      negative

已编辑。存在一些逻辑错误和语法错误。tapply返回了日期的整数值,正如你指出的,在数据缩减步骤中我使用了错误的列名。


我正在尝试创建一个缩减的数据集,只保留输血记录中的最后日期。我们随后只在 'Patient ID' 上合并,以便可以保留两个日期值。如果您将dput输出作为对问题的编辑添加,我将测试它。 - IRTFM
谢谢,我无法上传实际数据,但我会尝试重新创建示例。 - col. slade
好的,我已经粘贴了上面示例的 R 代码。实际上,患者可能有数百个测试结果,这就是为什么对于每次输血,将行数过滤到最接近的测试结果非常重要。 - col. slade
因此,澄清一下,最终的数据应该是:病人A在X天和Y天接受了输血(对于df_A)。在X天输血之前,他最近的检测结果是X(最接近第一次输血的检测日期,在df_B中)。在Y天输血之前,他最近的检测结果是Y(在第二次输血之前,也在df_B中。df_B还包含许多其他不需要用于最终输出的测试日期。 - col. slade
1
使用@jaysunice3401的建议,然后在每次转移之前进行拆分,并获取最后一个测试。 - IRTFM
显示剩余5条评论

0

好的,谢谢大家的帮助。这花费了我很多辛勤的劳动、奋斗和泪水,但这是我想出来的解决方案:

  1. 合并两个数据框:

df_AB <- merge(df_A, df_B, all.x = T)

df_AB:

  MRN Transfusion.Date  Test.Date   Test.Result
1   1       2000-01-01 1999-11-30      negative
2   1       2000-01-01 2000-01-15 700 copies/ul
3   1       2000-01-01 2000-01-27 900 copies/ul
4   1       2000-01-30 1999-11-30      negative
5   1       2000-01-30 2000-01-15 700 copies/ul
6   1       2000-01-30 2000-01-27 900 copies/ul
7   2       2003-04-01 2003-03-30      negative
8   3       2003-04-01       <NA>          <NA>

使用 dplyr
df_tests <- df_AB %>% 
  group_by(MRN, Transfusion.Date) %>%
  mutate(Time.Difference = Transfusion.Date - Test.Date) %>%
  filter(Time.Difference > 0) %>%
  arrange(Time.Difference) %>%
  summarize(Test.Date = Test.Date[1], Test.Result = Test.Result[1])

df_tests:

  MRN Transfusion.Date  Test.Date Test.Result
1   1       2000-01-01 1999-11-30    negative
2   1       2000-01-30 1999-11-30    negative
3   2       2003-04-01 2003-03-30    negative

再次使用合并操作以进行 MRN3:

df_desired <- merge(df_A, df_tests, all.x = T)

  MRN Transfusion.Date  Test.Date   Test.Result
1   1       2000-01-01 1999-11-30      negative
2   1       2000-01-30 2000-01-27 900 copies/ul
3   2       2003-04-01 2003-03-30      negative
4   3       2003-04-01       <NA>          <NA>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接