如何在igraph中合并重复vertex并保留边连接关系
解决igraph中合并重复顶点并保留所有边的问题
我太懂你折腾一整天找方法却卡壳的感受了——要把同组重复顶点(比如后缀不同的同一作者)合并成单个顶点,同时保住所有边的连接关系,确实有点绕,但用igraph原生的方法就能完美解决,根本不用导出CSV冒丢边的风险!
核心思路
本质上就是给每个要合并的顶点分配一个统一的分组标识,然后用igraph的contract_vertices()方法把同组顶点合并,同时让所有原来连接到这些重复顶点的边,自动关联到合并后的新顶点上。
具体步骤(附代码示例)
假设你的图对象是g,顶点的name属性就是你给出的那些带后缀的字符串(比如"R, 2000-1"),咱们一步步来:
1. 给顶点分配分组标识
首先得把每个顶点映射到它的目标分组(比如把"R, 2000-1"和"R, 2000-2"都归到"R, 2000"组):
from igraph import Graph from collections import defaultdict # 先模拟你的图(如果已经有现成的图,这部分可以跳过) vertices = ["R, 2000-1", "R, 2000-2", "J, 1999-1", "J, 1999-2", "J, 1999-3"] edges = [(0,2), (1,3), (1,4)] # 随便模拟一些边,对应原顶点的连接关系 g = Graph(n=len(vertices), edges=edges, vertex_attrs={"name": vertices}) # 提取每个顶点的基准分组名(去掉最后的"-数字"后缀) group_names = [] for v_name in g.vs["name"]: # 从右往左分割一次,取前面的部分作为基准名 base_name = v_name.rsplit("-", 1)[0].strip() group_names.append(base_name) # 把分组名转成数字ID(contract_vertices需要用数字分组) group_id_map = defaultdict(lambda: len(group_id_map)) group_ids = [group_id_map[name] for name in group_names]
2. 执行顶点合并,保留所有边
接下来用contract_vertices()完成合并,关键参数combine_edges决定了边的处理方式:
- 如果要保留所有重复边(比如原来有两条边分别连到
R,2000-1和R,2000-2,合并后变成两条边连到R,2000),设置combine_edges=None - 如果要合并重复边并统计数量(比如把同方向的边合并,权重设为边的总数),设置
combine_edges="sum" - 如果只需要保留一条边(不管原来有多少条),设置
combine_edges="first"
这里咱们用"sum"来兼顾连接关系和边的计数,代码如下:
# 合并顶点 merged_graph = g.contract_vertices(group_ids, combine_edges="sum") # 给合并后的顶点设置正确的名称(就是咱们的基准分组名) merged_graph.vs["name"] = list(group_id_map.keys())
3. 验证结果
现在你可以检查合并后的顶点和边,完全符合你的需求:
print("合并后的顶点:", merged_graph.vs["name"]) # 输出:合并后的顶点: ['R, 2000', 'J, 1999'] print("合并后的边列表:", merged_graph.get_edgelist()) # 输出会对应原来的边关联,比如(0,1),因为原R组顶点都连接到J组顶点
为啥导出CSV会丢边?
你之前尝试导出CSV再导入的方法出问题,大概率是因为导出时没有完整保留顶点的ID和边的关联关系,或者导入时没有正确映射新的顶点ID。用igraph原生的contract_vertices方法是最稳妥的——直接在图对象上操作,所有边的连接都会被自动继承,根本不会丢边。
内容的提问来源于stack exchange,提问作者Rafa Mesa
相关产品推荐
相关产品推荐

