R语言如何按指定条件匹配两个数据框的最优对应行
R语言双数据框条件匹配实现方案
完全可以通过fuzzyjoin包结合马氏距离计算实现你的需求,针对你的数据规模(仅数千行),以下两种方案均可高效运行:
前置准备
首先统一列名格式,计算马氏距离所需的协方差矩阵:
# 安装所需依赖包 install.packages("dplyr") # 如使用方案1需额外安装fuzzyjoin install.packages("fuzzyjoin") # 加载包 library(dplyr) # 替换列名中的空格为下划线,避免语法报错 colnames(df1) <- gsub(" ", "_", colnames(df1)) colnames(df2) <- gsub(" ", "_", colnames(df2)) # 提取四个数值指标列名 criteria_cols <- paste0("criteria_", 1:4) # 基于df2的数值列计算协方差矩阵,用于马氏距离计算 cov_matrix <- cov(df2[, criteria_cols])
方案1:基于fuzzyjoin包实现
逻辑更直观,符合你最初的工具选型预期:
library(fuzzyjoin) result <- df1 %>% # 先按type_1、type_2完全匹配,筛选所有符合基础条件的配对 fuzzy_left_join( df2, by = c("type_1", "type_2"), match_fun = list(`==`, `==`) ) %>% # 逐行计算配对的马氏距离 rowwise() %>% mutate( mahalanobis_dist = mahalanobis( x = c_across(all_of(paste0(criteria_cols, ".x"))), center = c_across(all_of(paste0(criteria_cols, ".y"))), cov = cov_matrix ) ) %>% ungroup() %>% # 按df1的每条记录分组,取距离最小的最优匹配 group_by(id.x) %>% slice_min(mahalanobis_dist, n = 1, with_ties = FALSE) %>% ungroup() # 可选:重命名列区分来源 colnames(result) <- gsub("\\.x", "_df1", colnames(result)) colnames(result) <- gsub("\\.y", "_df2", colnames(result))
方案2:轻量分组匹配实现(无需fuzzyjoin)
运行效率更高,适合后续数据规模扩展的场景:
# 按type_1、type_2拆分两个数据框为分组列表 df1_groups <- df1 %>% group_by(type_1, type_2) %>% group_split() df2_groups <- df2 %>% group_by(type_1, type_2) %>% group_split() # 定义分组内匹配函数 group_match <- function(df1_g) { # 匹配df2中对应type的分组 target_idx <- which(sapply(df2_groups, function(x) { x$type_1[1] == df1_g$type_1[1] && x$type_2[1] == df1_g$type_2[1] })) if(length(target_idx) == 0) return(NULL) df2_g <- df2_groups[[target_idx]] # 计算当前分组所有配对的马氏距离 dist_matrix <- apply(df1_g[, criteria_cols], 1, function(x) { apply(df2_g[, criteria_cols], 1, function(y) mahalanobis(x, y, cov_matrix)) }) # 取每个df1行的最小距离对应df2行 min_pos <- apply(dist_matrix, 2, which.min) # 合并匹配结果 cbind( df1_g %>% rename_with(~paste0(., "_df1")), df2_g[min_pos, ] %>% rename_with(~paste0(., "_df2")), mahalanobis_dist = dist_matrix[cbind(min_pos, 1:ncol(dist_matrix))] ) } # 遍历所有分组得到最终结果 final_result <- bind_rows(lapply(df1_groups, group_match))
可选替换
如果不需要使用马氏距离,可将上述代码中的距离计算逻辑替换为欧氏距离:sqrt(sum((x - y)^2)),或其他你需要的距离计算规则。
内容的提问来源于stack exchange,提问作者eBopBob
相关产品推荐
相关产品推荐

