补全DataFrame的ID组合列:生成同一对象的全部关联ID组合
问题描述
现有一个包含唯一ID的数据框,其中多个ID指向同一底层对象。需要构建新的数据框,保留原ID列,另一列补全所有指向同一对象的ID组合。当前数据的组合列存在缺失,比如x对应的组合仅包含x; y,但实际x和z也属于同一组。
当前数据:
library(tibble) df <- tibble(id = c("x", "y", "z", "q", "w", "p"), t = c("x; y", "x; y; z", "y; z", "q", "w; p", "p"))
输出如下:
# A tibble: 6 × 2 id t <chr> <chr> 1 x x; y 2 y x; y; z 3 z y; z 4 q q 5 w w; p 6 p p
期望结果:
desired_df <- tibble(id = c("x", "y", "z", "q", "w", "p"), t = c("x; y; z", "x; y; z", "x; y; z", "q", "w; p", "w; p"))
输出如下:
# A tibble: 6 × 2 id t <chr> <chr> 1 x x; y; z 2 y x; y; z 3 z x; y; z 4 q q 5 w w; p 6 p w; p
解决方案
这个问题本质是寻找图的连通分量:每个ID是一个节点,若两个ID出现在同一个组合中,则它们之间有边。我们需要找到每个节点所在的连通分量,再将分量内的ID拼接成指定格式的字符串。
用igraph包处理图结构效率较高,步骤如下:
library(tibble) library(igraph) library(dplyr) library(tidyr) # 1. 原始数据 df <- tibble(id = c("x", "y", "z", "q", "w", "p"), t = c("x; y", "x; y; z", "y; z", "q", "w; p", "p")) # 2. 拆分组合列,生成所有节点对(边) edges_df <- df %>% mutate(ids = strsplit(t, "; ")) %>% unnest(ids) %>% select(from = id, to = ids) %>% filter(from != to) # 3. 创建无向图并获取连通分量 graph <- graph_from_data_frame(edges_df, directed = FALSE) components <- components(graph) # 4. 匹配每个ID的连通分量,拼接成目标字符串 result_df <- df %>% mutate(component_id = components$membership[id]) %>% group_by(component_id) %>% mutate(t = paste(sort(unique(unlist(strsplit(t, "; ")))), collapse = "; ")) %>% ungroup() %>% select(id, t) # 输出结果 print(result_df)
运行后输出与期望结果一致:
# A tibble: 6 × 2 id t <chr> <chr> 1 x x; y; z 2 y x; y; z 3 z x; y; z 4 q q 5 w w; p 6 p w; p
补充说明
- 若不想依赖
igraph,可通过递归遍历关联ID实现,但大型数据框下效率远低于图算法。 - 代码中
sort()用于统一ID顺序,不需要的话可直接移除。
内容的提问来源于stack exchange,提问作者T. C. Nobel
相关产品推荐
相关产品推荐

