如何基于最近较小值实现两个数据集全连接?fuzzy_full_join报错处理
解决基于最近较小值的全连接合并问题
错误原因
你使用fuzzy_full_join时的报错,是因为match_fun参数传入了字符串'>',但该参数要求传入返回逻辑值的函数,而非字符串。正确的写法应该是function(x, y) x > y,用来判断左表的num是否大于右表的num.1。
但仅修正参数还不够,因为单纯的模糊连接会匹配所有满足num > num.1的记录,我们还需要进一步筛选出每个num对应的最近的较小值(即最大的num.1),同时保留两个表中无匹配的记录。
解决方案(附示例)
先构造示例数据集模拟你的场景:
# 示例左表:gps.pts gps.pts <- data.frame(num = c(3, 7, 12), value_gps = c("A", "B", "C")) # 示例右表:dive.sum dive.sum <- data.frame(num.1 = c(2, 5, 9, 15), value_dive = c("X", "Y", "Z", "W"))
方法1:用fuzzyjoin + dplyr实现
library(fuzzyjoin) library(dplyr) # 1. 执行模糊全连接,匹配所有num > num.1的记录 temp_join <- fuzzy_full_join( gps.pts, dive.sum, by = c('num' = 'num.1'), match_fun = function(x, y) x > y ) # 2. 筛选每个num对应的最大num.1(最近的较小值),同时保留右表无匹配的记录 final_result <- temp_join %>% # 对左表的每个num,保留最大的匹配num.1 group_by(num) %>% filter(is.na(num.1) | num.1 == max(num.1)) %>% ungroup() %>% # 补充右表中没有对应左表num的记录 bind_rows( dive.sum %>% filter(!num.1 %in% temp_join$num.1[!is.na(temp_join$num)]) %>% mutate(num = NA, value_gps = NA) ) %>% # 调整列顺序 select(num, value_gps, num.1, value_dive)
方法2:用data.table实现(更高效,适合大数据)
library(data.table) setDT(gps.pts) setDT(dive.sum) # 1. 匹配左表num对应的最近较小num.1 temp_result <- dive.sum[gps.pts, on = .(num.1 = num), roll = Inf] # 2. 补充右表无匹配的记录 final_result <- rbind( temp_result, dive.sum[!num.1 %in% temp_result$num.1[!is.na(temp_result$num)], .(num = NA, value_gps = NA, num.1, value_dive)] )
两种方法最终都会得到期望的合并结果:
| num | value_gps | num.1 | value_dive |
|---|---|---|---|
| 3 | A | 2 | X |
| 7 | B | 5 | Y |
| 12 | C | 9 | Z |
| NA | NA | 15 | W |
内容的提问来源于stack exchange,提问作者Rana
相关产品推荐
相关产品推荐

