【问题标题】:R: Using values from data frame A from a date prior to populate a row in data frame BR:在数据框 B 中填充一行之前,使用数据框 A 中的值
【发布时间】:2015-01-24 23:47:55
【问题描述】:

这可能非常复杂,我怀疑需要高级知识。我现在需要组合两种不同类型的 data.frame:

数据:

数据框 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 具有相同的行数(每次输血 1),并且最近的 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 对 data.frames 进行子集化。然后获取患者 1 的所有输血日期,检查哪个结果与每个元素的所有可用 test_dates 最接近,然后返回最接近的值。

我如何解释 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 天输血之前,他最近的测试结果是 X(最接近第一次输血的测试日期,在 df_B 中)。在Y天输血之前,他最近的测试结果是Y(在第二次输血之前,也在df_B中。df_B还包含一堆其他测试日期,最终输出不需要。

【问题讨论】:

  • 这应该让你开始 merge(df_A, df_B, by.x = "Patient.ID", by.y = "Patient.ID", all.x = TRUE) 然后尝试使用包 lubridate 添加日期差异列。
  • @jaysunice3401 谢谢你的回答,这就是我现在的位置,但是这样我得到了很多额外的行,因为测试结果比输血更多。我认为我需要做的是将 df_B 减少到相同数量的 pt ID 行,使用你告诉我的包......现在调查!
  • 也可以通过summarise()查看dplyr以方便group_by()摘要——按患者ID和日期的组合进行分组,然后获取与最小距离相对应的记录。
  • @jaysunice3401,你能再帮我一些吗,我不知道我需要如何将它与 BondedDust 的代码结合起来,(​​?似乎不需要润滑?)想出一个可行的解决方案.
  • @jaysunice3401 感谢您提到 dplyr,正如您所建议的,我使用了合并:df_AB % mutate(Date.difference = Test.Date - Transfusion.Date) 给了我所有的日期差异,这非常有帮助。现在尝试使用最小的负 Date.difference 对所有行进行子集化

标签: r join dataframe


【解决方案1】:

这里使用data.table的滚动连接:

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] 形式的连接,其中对于i 的每一行,x 的匹配行(如果有,否则不适用)以及i'返回 s 行。这就是我们所说的 equi-join。通过添加roll = TRUE,在发生不匹配的情况下,最后的观察结果将向前推进 (LOCF)。这就是我们所说的滚动连接。升序排序(由于setkey())确保最后一次观察是最近的日期。

HTH

【讨论】:

  • 哇,谢谢,看来我也确实需要查看 data.table,它非常简洁,滚动连接/LOCF 功能看起来很棒。特别感谢您解释 data.table 对代码的作用。有没有办法为滚动功能指定“边界”,例如仅在输血前一天或不超过 10 天进行测试时才滚动加入?再次,非常感谢!
  • 谢谢,很高兴知道。是的,roll = TRUE 等同于 roll=Inf - LOCF。您也可以使用roll = 10 或-10。 roll = -Inf 执行 NOCB - 下一个观察结果倒退。 roll = "nearest" 滚动到最接近的值。检查?data.table 和示例。我们也在处理creating detailed vignettes
【解决方案2】:

好的,谢谢大家的帮助。我付出了很多辛劳、鲜血、汗水和泪水,但这是我想出的解决方案:

  1. 合并两个数据框:

df_AB

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

using merge again for 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>

【讨论】:

    【解决方案3】:
     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 返回了 Dates 的整数值,正如您指出的那样,我在数据缩减步骤中使用了错误的列名。

    【讨论】:

    • BondedDust,你能解释一下这个解决方案吗?它似乎是 df_B 的子集,但我不确定它是否也可以在输血日期之前获得最接近的测试值? df_B 中也没有 Transfusion.Date,只有 Test.Date ?!?
    • 我试图为只有最后一个日期的输血记录创建一个简化的数据集。然后我们只在'Patient ID' 上合并,这样我们就可以保留两个日期值。如果您将示例中的 dput 输出添加为问题的编辑,我将对其进行测试。
    • 谢谢,我无法输入实际数据,但我会尝试重新创建示例
    • 好的,我为上面的示例粘贴了 R 代码。实际上,患者可能有数百个测试结果,这就是为什么在每次输血之前将行数过滤到最接近的测试结果对我来说很重要
    • 使用@jaysunice3401 的建议,然后在每次输血前分开,抓紧最后一次测试。
    猜你喜欢
    • 2013-12-23
    • 2016-09-07
    • 2022-01-04
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-17
    相关资源
    最近更新 更多