如何在tidyverse中基于OR条件连接两个R数据框?
在tidyverse中实现带OR条件的非SQL数据框连接
需求说明
需要基于以下OR条件连接两个数据框df_obs和df_event,最终将df_event的event列添加到df_obs中,结果需与示例df_res一致,且不使用SQL方法:
- 条件a:
obs_id与event_id匹配,且obs_date或event_date(或两者)为NA - 条件b:
obs_date与event_date完全相同,且obs_id或event_id(或两者)为NA
排除规则:若obs_id和event_id均非NA且不相等,或obs_date和event_date均非NA且不相等,则不匹配。
示例数据
library(tidyverse) df_obs <- tibble::tribble( ~obs, ~obs_date, ~obs_id, "a1", NA, 10L, "a2", "01/01/2000", NA, "b", "02/01/2000", NA, "a3", "03/01/2000", 10L ) df_event <- tibble::tribble( ~event, ~event_date, ~event_id, "A", "01/01/2000", 10L, "B", "02/01/2000", NA ) # 目标结果 df_res <- tibble::tribble( ~obs, ~obs_date, ~obs_id, ~event, "a1", NA, 10L, "A", "a2", "01/01/2000", NA, "A", "b", "02/01/2000", NA, "B", "a3", "03/01/2000", 10L, NA )
非SQL解决方案
通过交叉连接+条件过滤的方式实现,步骤如下:
- 生成两个数据框的所有可能行组合
- 按需求筛选有效匹配组合
- 合并回原始
df_obs,保留所有原始行并填充未匹配的event为NA
df_result <- df_obs %>% # 生成所有行组合 cross_join(df_event) %>% # 筛选符合条件a或条件b的有效匹配 filter( (obs_id == event_id & (is.na(obs_date) | is.na(event_date))) | (obs_date == event_date & (is.na(obs_id) | is.na(event_id))) ) %>% # 保留目标列 select(obs, obs_date, obs_id, event) %>% # 合并回原始df_obs,确保所有行保留 right_join(df_obs, by = c("obs", "obs_date", "obs_id")) %>% # 去重(避免同一行多匹配的情况) distinct(obs, obs_date, obs_id, .keep_all = TRUE) # 查看结果 df_result #> # A tibble: 4 × 4 #> obs obs_date obs_id event #> <chr> <chr> <int> <chr> #> 1 a1 <NA> 10 A #> 2 a2 01/01/2000 NA A #> 3 b 02/01/2000 NA B #> 4 a3 03/01/2000 10 <NA>
代码说明
cross_join():生成两个数据框的笛卡尔积,包含所有可能的行配对filter():严格按照需求的两个OR条件筛选,自动排除不符合规则的组合right_join():确保df_obs的所有原始行都被保留,未匹配到的行event列自动填充为NAdistinct():防止同一行出现多个匹配结果,增强代码鲁棒性
内容的提问来源于stack exchange,提问作者zoowalk
相关产品推荐
相关产品推荐

