R-基于最近日期合并数据框

Posted

技术标签:

【中文标题】R-基于最近日期合并数据框【英文标题】:R- merge dataframes based on recent dates 【发布时间】:2022-01-03 03:37:33 【问题描述】:

我有两个数据框:

在 DF1 中,对于每个 IDparam 已在不同日期记录。 在 DF2 中,对于每个 ID,都会给出多个日期。 对于每个ID,我想根据日期从DF1 中获取所有相应的paramvaluevalue 对应于给定参数的最新date1(在DF1之前date2(在DF2)或 如果没有这样的date1,则最近的value 之后 date2

DF1 是(我已经用 * 标记了结果的正确行):

  ID      date1 param  value
1 id1   1/1/2020    pA pA_1_1
2 id1   2/1/2020    pA pA_1_2 *
3 id1  17/1/2020    pA pA_1_3
4 id1  20/1/2020    pB pB_1_1 *
5 id1  21/1/2020    pB pB_1_2
6 id2 21/12/2022    pA pA_2_1 *
7 id2 22/12/2022    pA pA_2_2 
8 id2 18/12/2022    pB pB_2_1 *
9 id2 19/12/2022    pB pB_2_2 

DF2 是:

   ID      date2
1 id1  15/1/2020
2 id2 20/12/2020

结果应该是:

   ID      date2 param  value      date1
1 id1  15/1/2020    pA pA_1_2   2/1/2020
2 id1  15/1/2020    pB pB_1_1  20/1/2020
3 id2 20/12/2020    pA pA_2_1 21/12/2022
4 id2 20/12/2020    pB pB_2_1 18/12/2022

重现DF1DF2的代码:

DF1= data.frame(
  stringsAsFactors = FALSE,
                ID = c("id1","id1","id1","id1",
                       "id1","id2","id2","id2","id2"),
             date1 = c("1/1/2020","2/1/2020",
                       "17/1/2020","20/1/2020","21/1/2020","21/12/2022",
                       "22/12/2022","18/12/2022","19/12/2022"),
             param = c("pA", "pA", "pA", "pB", "pB", "pA", "pA", "pB", "pB"),
             value = c("pA_1_1","pA_1_2","pA_1_3",
                       "pB_1_1","pB_1_2","pA_2_1","pA_2_2","pB_2_1","pB_2_2")
)

DF2=data.frame(
  stringsAsFactors = FALSE,
                ID = c("id1", "id2"),
             date2 = c("15/1/2020", "20/12/2020")
)

【问题讨论】:

请检查 ID2 参数 pB 是否应该是第 9 行而不是第 8 行。因为 row8 是 date2 之后的最小日期。 【参考方案1】:

这是我的解决方案。我确信有一种方法可以用更少的代码来编写它(使用一个数据帧而不是两个数据帧,然后合并)。但我现在不知道。

library(tidyverse)
library(lubridate)
# Get before date2
before <-  DF1 %>%
  left_join(DF2,by = "ID") %>% 
  mutate(diff = dmy(date1)-dmy(date2)) %>% 
  mutate(Grp = data.table::rleid(param)) %>%
  filter(diff < 0) %>%
  group_by(Grp) %>%
  filter(diff == max(diff)) %>% 
  ungroup
# Get after date2
after <- DF1 %>%
  left_join(DF2,by = "ID") %>% 
  mutate(diff = dmy(date1)-dmy(date2)) %>% 
  mutate(Grp = data.table::rleid(param)) %>%
  filter(diff > 0) %>%
  group_by(Grp) %>%
  filter(! Grp %in% before$Grp, diff == min(diff)) %>% 
  ungroup

result <- bind_rows(before,after) %>% 
  select(ID,date2, param, value, date1) %>%
  arrange(ID, param)
 

说明:我正在使用 lubridate 库来比较日期。我执行相同的过程来创建两个数据帧 - 第一个(在 df 之前)用于完成第一个条件的组(DF1 中最接近的日期在 DF2 中的 date2 之前),第二个(在 df 之后)用于相反的组(最近DF1 中的日期在 DF2 中的 date2 之后)。

我先解释一下:

# Get before date2

    before <-  DF1 %>%
    left_join(DF2,by = "ID") %>% 
    mutate(diff = dmy(date1)-dmy(date2)) %>% 
    mutate(Grp = data.table::rleid(param)) %>%
    filter(diff < 0) %>%
    group_by(Grp) %>%
    filter(diff == max(diff)) %>% 
    ungroup

在这里,我们将 DF1 和 DF2 按 ID 合并,因此具有相同 ID 的行具有相同的 date2。然后,我们计算 date1-date2 的差异——首先我们使用dmy() 将字符转换为日期。因此,date2 之前的日期将是负差。使用data.table::rleid(param),我们枚举具有不同 ID 和参数的子组,因此我们可以知道子组。然后我们可以按那时分组并按它们过滤。

最后:

result <- bind_rows(before,after) %>% 
  select(ID,date2, param, value, date1) %>%
  arrange(ID, param)

我们按行绑定两个数据框并选择您要查找的列,以删除我们创建用于操作的列(组和过滤器)。 PS:我添加了arrange()来确保最终的df按ID和参数值排序。

【讨论】:

非常感谢罗伯托。你的评论也是对的。我在帖子中进行了更正。 @tzema 如果您在预期的 df 结果中也进行编辑以澄清 (19 -> 18),那就太好了。以防其他人搜索相关内容。

以上是关于R-基于最近日期合并数据框的主要内容,如果未能解决你的问题,请参考以下文章

从 R 中的两个数据框中选择参考日期之后的最近日期

如何在 R 中合并同一数据框中的行(基于特定列下的重复值)?

如何基于R中的2个日期时间变量合并行

从子集中选择观察值以基于 R 中的大型数据框创建新子集

在几天内按日期合并 2 个 Pandas 数据框?

是否有一个 R 函数可以计算自数据框中最近日期以来的天数?