如何实现支持数值百分比差异阈值的DataFrame反连接?
带数值百分比阈值的R语言Tibble差异对比实现
需求说明
需要对比两个混合类型的tibble,返回满足以下条件的差异行:
- 非数值型变量需精确匹配
- 数值型变量仅当差异超出设定百分比阈值(如20%)时才视为不匹配
- 已知
dplyr::anti_join仅支持精确匹配,无法满足数值阈值需求
给定数据:
library(dplyr) tbl1 <- tibble(var1 = c('r1', 'r2', 'r3', 'r4', 'r5'), var2 = c('apple', 'orange', 'banana', 'strawberry', 'lime'), var3 = c(1, 2, 3, 4, 5), var4 = c('yes', 'no', 'yes', 'yes', 'no')) tbl2 <- tibble(var1 = c('r6', 'r7', 'r8', 'r9', 'r10'), var2 = c('orange', 'banana', 'apple', 'lemon', 'strawberry'), var3 = c(2, 3, 1.5, 10, 4.1), var4 = c('no', 'yes', 'yes', 'no', 'yes'))
期望返回(20%阈值):
| var1 | var2 | var3 | var4 |
|---|---|---|---|
| r1 | apple | 1 | yes |
| r5 | lime | 5 | no |
解决方案
1. 手动实现(用dplyr,灵活可控)
核心思路:先按非数值匹配键做连接,筛选数值差异超阈值的行,再结合无匹配的行。
步骤代码:
# 设定百分比阈值 threshold_pct <- 0.2 # 1. 找出tbl1中在tbl2无匹配键(var2+var4)的行 no_match_rows <- tbl1 %>% anti_join(tbl2, by = c("var2", "var4")) # 2. 找出有匹配键但数值变量差异超阈值的行 numeric_mismatch_rows <- tbl1 %>% inner_join(tbl2, by = c("var2", "var4"), suffix = c("_tbl1", "_tbl2")) %>% mutate( # 计算数值变量的百分比差异 var3_pct_diff = abs(var3_tbl1 - var3_tbl2) / var3_tbl1, exceeds_threshold = var3_pct_diff > threshold_pct ) %>% filter(exceeds_threshold) %>% # 还原为原tbl1的列结构 select(var1 = var1_tbl1, var2, var3 = var3_tbl1, var4) # 合并两类差异行并排序 final_diff <- bind_rows(no_match_rows, numeric_mismatch_rows) %>% arrange(var1) # 查看结果 final_diff
输出结果:
# A tibble: 2 × 4 var1 var2 var3 var4 <chr> <chr> <dbl> <chr> 1 r1 apple 1 yes 2 r5 lime 5 no
2. 用现成包(compareDF)
compareDF包支持为数值变量设置公差,可简化差异对比:
library(compareDF) # 对比两个数据框,指定匹配键和数值公差(百分比) diff_result <- compare_df( tbl1, tbl2, by = c("var2", "var4"), num_tolerance = 0.2 # 对应20%阈值 ) # 提取符合要求的差异行 diff_result$comparison_df %>% filter(match == "mismatch" | is.na(match)) %>% select(var1 = var1.x, var2, var3 = var3.x, var4)
内容的提问来源于stack exchange,提问作者JemJem
相关产品推荐
相关产品推荐

