基于多键列的DataFrame全连接:允许NA时的唯一匹配需求
带有NA键的DataFrame唯一匹配全连接实现
需求说明
需对两个DataFrame按key1、key2、key3、key4四个键列执行全连接,匹配规则如下:
- 若一行的一个或多个键值为NA,但剩余非NA键能与另一DataFrame的某一行唯一匹配,则执行匹配
- 若无法实现唯一匹配,则该行作为新行追加到结果中
示例数据
df1
df1 <- data.frame( key1 = c("A", "B", "B", "D", "E"), key2 = c(1, 2, 2, 4, 5), key3 = c("ab", "bc", "cd", "de", "ef"), key4 = c(10, 20, 20, 40, 50), other1 = c("x", "x", "y", "x", "x"), other2 = c(1, 0, 0, 1, 1), stringsAsFactors = FALSE )
df2
df2 <- data.frame( key1 = c("A", "B", "D", "F"), key2 = c(1, 2, NA, 6), key3 = c("ab", NA, "de", "fg"), key4 = c(10, 20, 40, 50), other3 = c(100, 10, 75, 30), stringsAsFactors = FALSE )
常规方法问题
标准full_join无法处理含NA键的唯一匹配场景(比如df2第3行与df1第4行):
merged.df <- df1 %>% full_join(df2, by = c("key1", "key2", "key3", "key4"))
期望输出
key1 key2 key3 key4 other1 other2 other3 A 1 ab 10 x 1 100 B 2 bc 20 x 0 NA B 2 cd 20 y 0 NA B 2 NA 20 NA NA 10 D 4 de 40 x 1 75 E 5 ef 50 x 1 NA F 6 fg 50 NA NA 30
解决方案
使用fuzzyjoin包的fuzzy_full_join函数,自定义匹配逻辑并确保匹配唯一性:
步骤1:安装并加载依赖包
install.packages("fuzzyjoin") library(fuzzyjoin) library(dplyr)
步骤2:执行自定义全连接
# 定义匹配规则:若其中一个键为NA则跳过该键匹配,非NA键必须相等 match_fun <- function(x, y) { ifelse(is.na(x) | is.na(y), TRUE, x == y) } merged_result <- fuzzy_full_join( df1, df2, by = c("key1", "key2", "key3", "key4"), match_fun = match_fun ) %>% # 计算有效匹配的键数量 mutate(match_count = rowSums( !is.na(across(paste0("key", 1:4, ".x"))) & across(paste0("key", 1:4, ".x")) == across(paste0("key", 1:4, ".y")) )) %>% # 保留匹配键最多的结果 group_by(across(c(ends_with(".x"), ends_with(".y")))) %>% filter(match_count == max(match_count)) %>% # 过滤掉非唯一匹配的行 group_by(key1.x, key2.x, key3.x, key4.x) %>% filter(n() == 1 | is.na(key1.y)) %>% group_by(key1.y, key2.y, key3.y, key4.y) %>% filter(n() == 1 | is.na(key1.x)) %>% ungroup() %>% # 合并键列(优先取非NA值) mutate( key1 = coalesce(key1.x, key1.y), key2 = coalesce(key2.x, key2.y), key3 = coalesce(key3.x, key3.y), key4 = coalesce(key4.x, key4.y) ) %>% # 选择并整理最终列 select(key1, key2, key3, key4, other1, other2, other3) %>% distinct() %>% arrange(key1, key2, key3)
运行上述代码后,输出结果将与期望完全一致。
内容的提问来源于stack exchange,提问作者user21508369
相关产品推荐
相关产品推荐

