【问题标题】:join data.frames according to rule in R根据 R 中的规则加入 data.frames
【发布时间】:2020-10-28 01:41:03
【问题描述】:

我有以下 data.frame (data.frame_1),每个 clinic_code 从 2019 年 10 月 1 日到 2020 年 10 月 1 日,并且是具有许多变量的主要 data.frame(下面只有几个显示):

date            clinic_code    partner_code     
2019-10-01      A05            NA
2019-11-01      A05            NA
               .....
2020-10-01      A05            NA
2019-10-01      A12            NA
2019-11-01      A12            NA
2019-12-01      A12            NA
2020-01-01      A12            00044
2019-10-01      B17            NA
2019-11-01      B17            NA
               .....
2020-03-01      B17            00045
2020-04-01      B17            00045
2020-05-01      B17            00049
               .....
2020-10-01      B17            00049

然后是从 2019-10-01 到 2020-02-31 的旧版本 (data.frame_2):

clinic_code    partner_code    partnership_start_date    partnership_end_date
A05            00033           2019-10-01                NA
A12            00001           2019-10-01                NA
A12            00001           2019-10-01                2019-12-31 
A12            00044           2020-01-01                NA
B17            00002           2019-10-01                NA

我想用data.frame_2来填充data.frame_1中partner_code的空格。 (+ 来自主 data.frame_1 的所有其他变量):

date             clinic_code   partner_code  
2019-10-01       A05           00033
2019-11-01       A05           00033
                .....
2020-09-01       A05           00033 
2020-10-01       A05           00033
2019-10-01       A12           00001 
2019-11-01       A12           00001         
2019-12-01       A12           00001        
2020-01-01       A12           00044
                              .......
2020-10-01       A12           00044
2019-10-01       B17           00002
2019-11-01       B17           00002
2019-12-01       B17           00002
2020-01-01       B17           00002
2020-02-01       B17           00002
                              .......
2020-03-01       B17           00045
2020-04-01       B17           00045 
2020-05-01       B17           00049 
                              .......
2020-10-01       B17           00049

我的标准是:在 partner_code 上填写 data.frame_1 上来自 data.frame 2 的 partner_code 上的任何额外信息。我的 3 种可能的情况:

  1. A05 - data.frame_1 没有关于 A05 的 partner_code 的任何信息,我使用从 partnership_start_date (2019-10-01) 到 partnership_end_date 的 data.frame_2 中的信息(如果不适用,则意味着没有结束)
  2. A12 - data.frame_1 在特定日期 (2020-01-01) 有一些关于 partner_code 的信息,但之前没有信息,所以我使用来自 partnership_start_date (2019-10-01) 的 data.frame_2 的信息) 直到 partnership_end_date (2019-12-31)。
  3. B17 - data.frame_1 从特定日期 (2020-03-01) 有一些关于 partner_code 的信息,但之前没有信息,所以我使用来自 partnership_start_date (2019-10-01) 的 data.frame_2 的信息) 直到partnership_end_date(NA=没有结束;在这种情况下,因为 data.frame_1 中有一个来自 2020-03-01 的 partner_code,我不想覆盖它并留下 data.frame_1 中的任何内容。

【问题讨论】:

  • 您的填写标准是什么?我无法从你的例子中推断出它们。例如,为什么在您的预期输出中有这么多行的临床代码 A05,但 data.frame_1 或 data.frame_2 只显示一行?
  • 非常感谢 ekoam,如果不清楚,很抱歉 - 我刚刚用标准更新了我的问题。关于您的具体问题:我的 data.frame_1 中的每个 Clinic_code 从 2019-10-01 到 2020-10-01 - 请查看更新后的 data.frame_1
  • 嗨,我有一些想法,但需要进一步澄清。 data.frame_2 中的第 2 行和第 3 行显示了 Clinic_code 和 partner_code 的相同值。为什么data.frame_1中的A12填写第3行而不选择第2行?
  • 抱歉没有解释。这是因为 data.frame_2 加入了 2 个 data.frames(一个来自 2 月,一个来自 3 月),有时我们会看到这种情况,其中 2 月(第 2 行)伙伴关系仍在进行中(NA),但随后在 3 月(第 3 行)它结束了。当相同的诊所代码、合作伙伴代码和合作伙伴开始日期以及为合作伙伴结束日期设置的日期有另一行时,也许我需要删除那些带有 NA 的行(如第 2 行)。不确定您是否可以考虑其他方法来解决此问题。

标签: r dataframe join merge


【解决方案1】:

我想这就是你想要的

library(dplyr)
library(tidyr)

prep <- 
  . %>% 
  as_tibble() %>% 
  mutate(across(ends_with("date"), as.Date))

prep(data.frame_2) %>% 
  group_by(clinic_code, partner_code) %>% 
  slice(which.max(order(partnership_end_date, na.last = FALSE))) %>% 
  mutate(partnership_end_date = if_else(is.na(partnership_end_date), as.Date("2020-10-01"), partnership_end_date)) %>% 
  expand(date = seq.Date(partnership_start_date, partnership_end_date, by = "month"), clinic_code, partner_code) %>% 
  left_join(prep(data.frame_1), ., by = c("date", "clinic_code"), suffix = c("", ".2")) %>% 
  mutate(partner_code = coalesce(partner_code, partner_code.2)) %>% 
  select(-partner_code.2)

输出

一目了然

# A tibble: 39 x 3
   date       clinic_code partner_code
   <date>     <chr>       <chr>       
 1 2019-10-01 A05         00033       
 2 2019-11-01 A05         00033       
 3 2019-12-01 A05         00033       
 4 2020-01-01 A05         00033       
 5 2020-02-01 A05         00033       
 6 2020-03-01 A05         00033       
 7 2020-04-01 A05         00033       
 8 2020-05-01 A05         00033       
 9 2020-06-01 A05         00033       
10 2020-07-01 A05         00033       
# ... with 29 more rows

全图

         date clinic_code partner_code
1  2019-10-01         A05        00033
2  2019-11-01         A05        00033
3  2019-12-01         A05        00033
4  2020-01-01         A05        00033
5  2020-02-01         A05        00033
6  2020-03-01         A05        00033
7  2020-04-01         A05        00033
8  2020-05-01         A05        00033
9  2020-06-01         A05        00033
10 2020-07-01         A05        00033
11 2020-08-01         A05        00033
12 2020-09-01         A05        00033
13 2020-10-01         A05        00033
14 2019-10-01         A12        00001
15 2019-11-01         A12        00001
16 2019-12-01         A12        00001
17 2020-01-01         A12        00044
18 2020-02-01         A12        00044
19 2020-03-01         A12        00044
20 2020-04-01         A12        00044
21 2020-05-01         A12        00044
22 2020-06-01         A12        00044
23 2020-07-01         A12        00044
24 2020-08-01         A12        00044
25 2020-09-01         A12        00044
26 2020-10-01         A12        00044
27 2019-10-01         B17        00002
28 2019-11-01         B17        00002
29 2019-12-01         B17        00002
30 2020-01-01         B17        00002
31 2020-02-01         B17        00002
32 2020-03-01         B17        00045
33 2020-04-01         B17        00045
34 2020-05-01         B17        00049
35 2020-06-01         B17        00002
36 2020-07-01         B17        00002
37 2020-08-01         B17        00002
38 2020-09-01         B17        00002
39 2020-10-01         B17        00049

一些关键步骤

  1. slice(which.max(order(...

查找每组 Clinic_code 和 partner_code 的最后一个合作伙伴关系结束日期。使用 na.last = FALSE 将 NA 放置在 before 非 NA 值之前。这样,我们总能得到一个 NA 或最后一个非 NA 的合作结束日期(如果有的话)。

  1. mutate(* = if_else(is.na(*), as.Date("2020-10-01"), *))

将 NA 视为 2020-10-01,因为这是最晚的日期。

  1. expand(date = seq.Date(partnership_start_date, partnership_end_date, by = "month"), ...)

将 data.frame_2 中的每个开始-结束日期对展开为一个完整的序列。展开后,data.frame_2 和 data.frame_1 格式相同,如下图

# A tibble: 39 x 3
# Groups:   clinic_code, partner_code [4]
   date       clinic_code partner_code
   <date>     <chr>       <chr>       
 1 2019-10-01 A05         00033       
 2 2019-11-01 A05         00033       
 3 2019-12-01 A05         00033       
 4 2020-01-01 A05         00033       
 5 2020-02-01 A05         00033       
 6 2020-03-01 A05         00033       
 7 2020-04-01 A05         00033       
 8 2020-05-01 A05         00033       
 9 2020-06-01 A05         00033       
10 2020-07-01 A05         00033       
# ... with 29 more rows
  1. left_join(prep(data.frame_1), ., by = c("date", "clinic_code"), suffix = c("", ".2"))

在每个匹配的日期和诊所代码上加入 data.frame_1 和 data.frame_2(“.”代表 data.frame_2)。生成的数据帧将有两个“partner_code”列:一个名为“partner_code”,来自 data.frame_1,另一个名为“partner_code.2”,来自 data.frame_2。然后,我们使用coalesce() 将 partner_code 中的缺失值替换为 partner_code.2 中的值。

数据

data.frame_1和data.frame_2如下

data.frame_1

structure(list(date = c("2019-10-01", "2019-11-01", "2019-12-01", 
"2020-01-01", "2020-02-01", "2020-03-01", "2020-04-01", "2020-05-01", 
"2020-06-01", "2020-07-01", "2020-08-01", "2020-09-01", "2020-10-01", 
"2019-10-01", "2019-11-01", "2019-12-01", "2020-01-01", "2020-02-01", 
"2020-03-01", "2020-04-01", "2020-05-01", "2020-06-01", "2020-07-01", 
"2020-08-01", "2020-09-01", "2020-10-01", "2019-10-01", "2019-11-01", 
"2019-12-01", "2020-01-01", "2020-02-01", "2020-03-01", "2020-04-01", 
"2020-05-01", "2020-06-01", "2020-07-01", "2020-08-01", "2020-09-01", 
"2020-10-01"), clinic_code = c("A05", "A05", "A05", "A05", "A05", 
"A05", "A05", "A05", "A05", "A05", "A05", "A05", "A05", "A12", 
"A12", "A12", "A12", "A12", "A12", "A12", "A12", "A12", "A12", 
"A12", "A12", "A12", "B17", "B17", "B17", "B17", "B17", "B17", 
"B17", "B17", "B17", "B17", "B17", "B17", "B17"), partner_code = c(NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "00044", 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "00045", 
"00045", "00049", NA, NA, NA, NA, "00049")), row.names = c(NA, 
39L), class = "data.frame")

data.frame_2

structure(list(clinic_code = c("A05", "A12", "A12", "A12", "B17"
), partner_code = c("00033", "00001", "00001", "00044", "00002"
), partnership_start_date = c("2019-10-01", "2019-10-01", "2019-10-01", 
"2020-01-01", "2019-10-01"), partnership_end_date = c(NA, NA, 
"2019-12-31", NA, NA)), class = "data.frame", row.names = c(NA, 
-5L))

【讨论】:

  • 非常感谢@ekoam 抽出时间来看看这个。似乎“跨越”功能仍然只在 dplyr 的开发版本中可用,在 CRAN 上还没有。有没有其他方法可以代替使用“交叉”?它找不到'across'函数,所以我得到一个错误。
  • 很高兴将您的 dplyr 软件包更新到最新的 CRAN 版本。跨应该可用。
  • 旧语法mutate_at(vars(ends_with("date")), as.Date)
  • 我刚刚完成 install.library("tidyverse") & library(tidyverse) 然后在顶部 install.library("dplyr") & library(dplyr) 我假设它会自动安装最新的克兰版?但我不断收到“跨越”不存在的信息。无论如何,使用较旧的语法有效,谢谢!我现在将检查输出。
  • 这是很棒的 ekoam,我已经做了一些检查,一切似乎都按预期工作。谢谢!我意识到那些具有相同临床代码、合作伙伴代码和合作伙伴开始日期的 NA 的行出现在我的数据集上合作伙伴结束日期的行之后(与我之前的问题相反),并且因为您在“一些关键”上的第一点步骤”,为避免任何问题,我在运行您的代码之前从 data.frame_2 中删除了这些行。
【解决方案2】:

您可以尝试使用fuzzyjoin根据范围加入:

library(dplyr)

df2 %>%
  mutate(partnership_end_date = replace(partnership_end_date, 
                                is.na(partnership_end_date), Sys.Date())) %>%
  fuzzyjoin::fuzzy_right_join(df1, by = c('clinic_code', 
               'partnership_start_date' = 'date', 'partnership_end_date' = 'date'), 
                match_fun = list(`==`, `<=`, `>=`)) %>%
  mutate(partner_code = coalesce(partner_code.y, partner_code.x))

【讨论】:

  • 非常感谢 Ronak 提出的解决方案。我还必须加载fuzzyjoin 包,但随后出现错误提示“错误:向量内存已用尽(已达到限制?)”。
  • 您的数据有多大?行数与列数?
  • 我觉得不大。 data.frame_1 = 88761 obs。 12 个变量和 data.frame_2 = 6824 obs。共 5 个变量,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-04
  • 2019-03-18
  • 1970-01-01
相关资源
最近更新 更多