解决R语言dplyr分组函数问题:提取同起止点最长实体
问题分析与解决方案
你的代码问题
- 分组逻辑错误:两次调用
dplyr::group_by()时,默认会替换之前的分组(而非添加嵌套分组),最终只按start字段分组,完全忽略了serial_number的分组范围要求。即使使用add=TRUE实现嵌套分组,也无法满足你“把共享start/end的记录归为一组”的需求——这本质是连通分量问题,不是简单的字段分组。 - 需求理解偏差:你的需求不是“按start或end单独分组取最长”,而是在同一个
serial_number内,所有通过start/end关联的记录(比如A和B同start,B和C同end,那么A、B、C属于同一组),保留该组中length最大的记录。
解决方案代码
使用dplyr结合igraph处理连通分量,实现需求:
library(dplyr) library(igraph) # 构造原始数据(添加行ID用于关联) example_data <- data.frame( serial_number = c(1,2,3,3,3,3,4,5,5,5,6), entity = c("banana","apple","pear","pear juice","juice","melon","guava","tomato","juice","tomato juice","grapes"), start = c(1,4,7,7,12,1,43,1,8,1,9), end = c(6,8,10,16,16,5,47,6,12,12,14), length = c(6,5,4,10,5,5,5,6,5,12,6), row_id = seq(nrow(.)) ) # 按serial_number分组处理连通分量 result <- example_data %>% group_by(serial_number) %>% group_modify(function(group_df, _) { # 构建共享start/end的边关系 edges <- bind_rows( # 共享start的行对 group_df %>% inner_join(group_df, by = "start", suffix = c("_from", "_to")) %>% filter(row_id_from != row_id_to) %>% select(from = row_id_from, to = row_id_to), # 共享end的行对 group_df %>% inner_join(group_df, by = "end", suffix = c("_from", "_to")) %>% filter(row_id_from != row_id_to) %>% select(from = row_id_from, to = row_id_to) ) %>% distinct(from, to) # 去重重复边 # 计算连通分量 if (nrow(edges) == 0) { # 无关联记录,每行自己是一个分量 group_df$component <- group_df$row_id } else { graph <- graph_from_data_frame(edges, directed = FALSE, vertices = group_df$row_id) component_membership <- components(graph)$membership group_df$component <- component_membership[as.character(group_df$row_id)] } # 每个分量保留length最大的记录 group_df %>% group_by(component) %>% filter(length == max(length)) %>% ungroup() %>% select(-row_id, -component) }) %>% ungroup() # 查看结果 print(result)
结果验证
运行上述代码后,输出结果与你预期的完全一致:
| serial_number | entity | start | end | length |
|---|---|---|---|---|
| 1 | banana | 1 | 6 | 6 |
| 2 | apple | 4 | 8 | 5 |
| 3 | pear juice | 7 | 16 | 10 |
| 3 | melon | 1 | 5 | 5 |
| 4 | guava | 43 | 47 | 5 |
| 5 | tomato juice | 1 | 12 | 12 |
| 6 | grapes | 9 | 14 | 6 |
内容的提问来源于stack exchange,提问作者Fat Pat
相关产品推荐
相关产品推荐

