【问题标题】:python igraph, graph intersection/union based on vertex names/labelspython igraph,基于顶点名称/标签的图形交集/联合
【发布时间】:2016-12-22 13:09:21
【问题描述】:

我对 Python 和 igraph 还是很陌生。对于我的学士论文,我必须比较图表,从而确定图表的交集和并集。我尝试了以下方法:

from igraph import *
import json

with open('test_graphs.json') as data_file:
    data = json.load(data_file)

test1 = data['test1']
test2 = data['test2']

t1 = Graph(directed=True)
for v in test1:
    t1.add_vertex(v)
for v in test1:
    for o in test1[v]:
        t1.add_edge(v, o)
print(t1)

t2 = Graph(directed=True)
for v in test2:
    t2.add_vertex(v)
for v in test2:
    for o in test2[v]:
        t2.add_edge(v, o)

print(t2)

gr = t1.intersection(t2)
print(gr)

我的json文件在哪里:

{
    "test1" : {
        "A": ["B","C"],
        "B": [],
        "C": []
    },

    "test2" : {
        "A": ["B","D"],
        "B": [],
        "D": []
    }
}

我预计交叉点的输出是 A->B。但是出现了以下输出:

IGRAPH DN-- 3 2 --
+ attr: name (v)
+ edges (vertex names):
A->B, A->C
IGRAPH DN-- 3 2 --
+ attr: name (v)
+ edges (vertex names):
A->B, A->D
IGRAPH D--- 3 2 --
+ edges:
2->0 2->1

第一个打印的图表显示,两个输入图表都按预期工作(即使很难,我也不明白“attr”是从哪里来的?)。 但是输出图并不认为我的两个图中的顶点 A 和 B 是相同的,而 C 和 D 是相同的。所以我的问题是:考虑到顶点的标签,我如何确定图形的交集(和模拟并集)。

【问题讨论】:

标签: python graph igraph intersection


【解决方案1】:

在由 paqmo 链接的问题Perform union of graphs based on vertex names Python igraph 中,维护者说此功能(按顶点名称的联合或交叉)在 python-igraph 中不可用。所以你必须自己编写函数来完成。

这是工会的一种方法。将孤立的顶点添加到两个图中,使它们都具有相同的顶点名称集,然后置换它们的两个顶点集,以使名称以相同的顺序出现。然后标准的union 方法(相当于| 运算符)将做正确的事情。不幸的是,union 方法不维护属性,因此您必须添加回名称以及您需要的任何其他属性。

def named_union(graph1, graph2):
    A = graph1.copy()
    B = graph2.copy() # so added vertices don't affect original graphs
    Anams = set(A.vs['name'])
    Bnams = set(B.vs['name'])
    A.add_vertices(list(Bnams - Anams))
    B.add_vertices(list(Anams - Bnams))
    nams = sorted(Anams | Bnams)
    Aind = [nams.index(nm) for nm in A.vs['name']]
    Bind = [nams.index(nm) for nm in B.vs['name']]
    A = A.permute_vertices(Aind) # permute vertices to come in same order as in nams
    B = B.permute_vertices(Bind) # ditto
    Z = A | B
    Z.vs['name'] = nams
    return Z

我们可以对交叉点做类似的事情,除了我们从每个图中删除不在另一个图中的顶点,然后在使用标准 intersection 方法之前,在两个图中排列剩余顶点以相同的顺序出现(或& 运算符)。

def named_intersect(graph1, graph2):
    A = graph1.copy()
    B = graph2.copy() # so removed vertices don't affect original graphs
    Anams = set(A.vs['name'])
    Bnams = set(B.vs['name'])
    A.delete_vertices(Anams - Bnams)
    B.delete_vertices(Bnams - Anams)
    nams = sorted(Anams & Bnams)
    Aind = [nams.index(nm) for nm in A.vs['name']]
    Bind = [nams.index(nm) for nm in B.vs['name']]
    A = A.permute_vertices(Aind)
    B = B.permute_vertices(Bind)
    Z = A & B
    Z.vs['name'] = nams
    return Z

琐事:delete_vertices 在给定集合时会做正确的事,但 add_vertices 不会,除非我们先将集合变成列表。例如,包含两个元素“A”和“B”的集合会导致添加两个顶点,均名为 {'A', 'B'}——这似乎是一个错误。

【讨论】: