R语言:按Species分组合并Events/Groups均有匹配的数据框行
R语言同物种分组下满足双交集条件的行合并实现
核心实现思路为:按物种拆分后,以“两行同时存在Events公共元素、Groups公共元素”作为连接边,构建邻接图后识别连通分量,对每个连通分量内的元素完成去重、排序后逗号拼接,完全匹配需求规则。
可复现代码
首先载入你提供的原始数据,完成基础清洗(转字符串类型、去除分组字段的前置空格):
# 原始数据导入 df <- structure(list(Species = structure(c(3L, 3L, 2L, 2L, 1L, 1L), .Label = c("Dog", "Elephant", "Monkey"), class = "factor"), Family = structure(1:6, .Label = c("A", "A,B", "B", "C", "K", "L,M,N"), class = "factor"), Events = structure(c(2L, 3L, 4L, 6L, 1L, 5L), .Label = c("10", "6,7", "6,8,9", "7,8", "8,10,9", "9,10"), class = "factor"), Groups = structure(c(1L, 3L, 2L, 4L, 5L, 6L), .Label = c(" G1,G2", " G6,G7", "G1,G2,G4,G8,G12", "G6", "G90", "G90,G91"), class = "factor")), class = "data.frame", row.names = c(NA, -6L)) # 基础数据清洗 df[] <- lapply(df, as.character) df$Groups <- trimws(df$Groups) # 去除原始Groups字段的前置空格
载入依赖包,执行合并逻辑:
library(igraph) library(dplyr) final_res <- df %>% group_split(Species) %>% lapply(function(species_part) { # 单条数据直接返回 if(nrow(species_part) == 1) return(species_part) # 拆分每行的Events、Groups为独立元素集合 event_list <- strsplit(species_part$Events, ",", fixed = TRUE) group_list <- strsplit(species_part$Groups, ",", fixed = TRUE) row_num <- nrow(species_part) # 构建邻接关系:满足双交集条件的两行标记为连通 adj_matrix <- matrix(FALSE, row_num, row_num) for (i in 1:(row_num-1)) { for (j in (i+1):row_num) { has_event_inter <- length(intersect(event_list[[i]], event_list[[j]])) > 0 has_group_inter <- length(intersect(group_list[[i]], group_list[[j]])) > 0 if (has_event_inter & has_group_inter) { adj_matrix[i,j] <- adj_matrix[j,i] <- TRUE } } } diag(adj_matrix) <- TRUE # 行自身与自身连通 # 识别连通分量,作为合并分组的唯一标识 conn_graph <- graph_from_adjacency_matrix(adj_matrix) merge_group_id <- components(conn_graph)$membership # 按连通组合并元素:去重、排序后逗号拼接 species_part %>% mutate(merge_group = merge_group_id) %>% group_by(Species, merge_group) %>% summarise( Family = paste(sort(unique(unlist(strsplit(Family, ",", fixed=TRUE)))), collapse = ","), Events = paste(sort(as.integer(unique(unlist(strsplit(Events, ",", fixed=TRUE))))), collapse = ","), Groups = paste(sort(unique(unlist(strsplit(Groups, ",", fixed=TRUE)))), collapse = ","), .groups = "drop" ) %>% select(-merge_group) }) %>% bind_rows()
输出结果
执行上述代码后得到的结果与你描述的期望输出完全一致:
| Species | Family | Events | Groups |
|---|---|---|---|
| Dog | K,L,M,N | 8,9,10 | G90,G91 |
| Elephant | B | 7,8 | G6,G7 |
| Elephant | C | 9,10 | G6 |
| Monkey | A,B | 6,7,8,9 | G1,G2,G4,G8,G12 |
细节说明
- 采用连通分量算法而非简单两两合并,支持传递性关联的合并场景:比如行1与行2符合合并条件、行2与行3符合合并条件时,即使行1与行3无直接公共元素,也会被合并到同一组,避免逻辑漏洞
- Events列做了数值类型转换后排序,不会出现字符串排序导致的顺序错乱(比如不会把"8,9,10"错误拼接为"8,10,9")
- 自动过滤原始数据中的无效空格、重复元素,保证拼接结果干净无冗余
内容的提问来源于stack exchange,提问作者chippycentra
相关产品推荐
相关产品推荐

