R语言基于多条件匹配两个数据框并打分类标签的实现问题
R语言多条件匹配为DataFrame打标签
现有数据集
# 数据集df1 cycle <- c(160, 160, 150, 158, 180) split1 <- c(2, 2,4, 6, 8) split2 <- c(10,10, 12, 14, 16) df1 <- data.frame(cycle, split1, split2) # 数据集df2 cycle <- c(160,150,190,180,161,150,140,179) split1 <- c(2,4,12,8,2,4,32,8) split2 <- c(10, 12, 18, 16, 10, 12, 21, 16) df2 <- data.frame(cycle, split1, split2)
匹配规则
需要为df2每一行添加Type标签,判断规则如下:
- 规则1:cycle、split1、split2三列取值和df1某行完全一致,标记为Same
- 规则2:split1、split2和df1某行完全一致,仅cycle取值差值为±1,也标记为Same
- 不满足以上两种情况标记为Different
预期输出
cycle split1 split2 Type 1 160 2 10 Same 2 150 4 12 Same 3 190 12 18 Different 4 180 8 16 Same 5 161 2 10 Same 6 150 4 12 Same 7 140 32 21 Different 8 179 8 16 Same
现有实现问题
原实现仅能匹配三列完全一致的场景,无法覆盖cycle值差±1的规则:
# 原有仅支持规则1的代码 df1<- df1 %>% mutate(key = paste0(cycle,split1, split2, "_")) df2<- df2 %>% mutate(key = paste0(cycle,split1, split2, "_")) df2 %>% mutate(Type = ifelse(df2$key %in% df1$key, 'same', 'different'))%>% select(-key)
高效实现方案
方案1:fuzzyjoin模糊匹配(大数据量推荐)
依赖fuzzyjoin包实现高性能模糊匹配,避免逐行循环的性能损耗:
library(dplyr) library(fuzzyjoin) result <- df2 %>% # 和去重后的df1做模糊左连接 fuzzy_left_join( df1 %>% distinct(cycle, split1, split2), by = c("split1" = "split1", "split2" = "split2", "cycle" = "cycle"), # 分别定义三个字段的匹配规则 match_fun = list( `==`, `==`, function(x,y) abs(x - y) <= 1 ) ) %>% # 匹配到的就标记为Same mutate(Type = ifelse(!is.na(cycle.y), "Same", "Different")) %>% # 保留需要的字段 select(cycle = cycle.x, split1 = split1.x, split2 = split2.x, Type)
方案2:无额外依赖实现(小数据量适用)
不需要安装额外包,用rowwise逐行判断即可:
library(dplyr) result <- df2 %>% rowwise() %>% mutate( # 检查当前行是否在df1中符合匹配规则 match_flag = any(df1$split1 == split1 & df1$split2 == split2 & abs(df1$cycle - cycle) <= 1), Type = ifelse(match_flag, "Same", "Different") ) %>% select(-match_flag) %>% ungroup()
两种方案输出结果都和预期完全一致。
内容的提问来源于stack exchange,提问作者Sorath Abbasi
相关产品推荐
相关产品推荐

