如何让R中dplyr的full_join将NA作为通配符进行匹配?
在dplyr的full_join中将NA视为通配符实现模糊匹配
dplyr的full_join默认仅支持精确匹配,连接列中的NA只能匹配另一数据框对应列的NA,无法作为通配符匹配任意值。要实现需求中的NA通配匹配,可以通过以下两种方式解决:
方法一:使用fuzzyjoin包自定义匹配规则
fuzzyjoin包提供了模糊连接功能,允许我们自定义列的匹配逻辑,非常适合处理NA作为通配符的场景。
步骤1:安装并加载依赖包
# 若未安装fuzzyjoin则先安装 install.packages("fuzzyjoin") library(dplyr) library(fuzzyjoin)
步骤2:定义示例数据
x = data.frame(class = c("A", "B", "B", "C"), flags = c(NA, "individual", "group", NA), interest = c(0.04, 0.03, 0.02, 0.05)) y = data.frame(class = c("A", "A", "B", "B", "C"), flags = c("individual", "group", "individual", "group", NA), costs = c(0.05, 0.025, 0.03, 0.02, 0.01))
步骤3:执行模糊全连接
通过match_fun参数定义匹配规则:class列精确匹配;flags列只要其中一方为NA,或者值相等即匹配。
result <- fuzzy_full_join( x, y, by = c("class", "flags"), match_fun = list( `==`, # class列严格相等 function(x_col, y_col) is.na(x_col) | is.na(y_col) | x_col == y_col ) ) %>% # 去重并清理无效行,整理结果结构 distinct(class, flags, interest, costs, .keep_all = TRUE) %>% filter(!(is.na(interest) & is.na(costs))) %>% arrange(class, flags) # 查看结果 result
运行后得到期望的输出:
class flags interest costs 1 A individual 0.04 0.050 2 A group 0.04 0.025 3 B individual 0.03 0.030 4 B group 0.02 0.020 5 C <NA> 0.05 0.010
方法二:手动扩展NA行后再连接
如果不想额外安装包,可以先将含NA的行扩展为对应class下的所有可能值,再执行常规的full_join。
# 提取每个class对应的所有flags取值 class_flags <- y %>% group_by(class) %>% summarise(flags_list = list(unique(flags))) # 扩展x中flags为NA的行 x_expanded <- x %>% left_join(class_flags, by = "class") %>% tidyr::unnest(flags_list) %>% mutate(flags = ifelse(is.na(flags), flags_list, flags)) %>% select(-flags_list) %>% distinct() # 执行全连接并整理结果 result_manual <- full_join(x_expanded, y, by = c("class", "flags")) %>% arrange(class, flags) # 查看结果 result_manual
这种方式同样能得到符合预期的结果,但逻辑相对繁琐,适合无法安装额外包的场景。
内容的提问来源于stack exchange,提问作者Reinhold Kainhofer
相关产品推荐
相关产品推荐

