如何用networkx提取给定图的所有可能诱导子图

10 投票
2 回答
10708 浏览
提问于 2025-04-17 20:50

我想知道能不能用networkx这个库来提取一个大图中所有可能的特定节点数的诱导子图(也叫图小块),或者有没有其他的工具可以做到这一点?比如说,如果我有一个大图,用networkx的邻接表格式表示,

图G:

1 2 3 7
2 1 4
3 1 4 6 5
4 2 3 5
5 3 4 6
6 3 5 7
7 1 6

看起来会像这样:

enter image description here

如果我想提取一个包含3个节点的小图,算法应该返回给我:

子图1:

1 2 3
2 1
3 1

[(1,2),(1,3)] enter image description here 子图2:

1 3 7
3 1
7 1

[(1,3),(1,7)] enter image description here 子图3:

3 4 5
4 3 5
5 3 4

[(3,4),(3,5),(4,5)] enter image description here

子图4、子图5、子图6……

以下是@Hooked建议的问题代码。假设n=3

import itertools
target = nx.complete_graph(3)
for sub_nodes in itertools.combinations(g.nodes(),len(target.nodes())):
    subg = g.subgraph(sub_nodes)
    if nx.is_connected(subg):
        print subg.edges()

输出结果会像这样:

[(1, 2), (1, 3)]
[(1, 2), (2, 4)]
[(1, 2), (1, 7)]
[(1, 3), (3, 4)]
[(1, 3), (3, 5)]
[(1, 3), (3, 6)]
[(1, 3), (1, 7)]
[(1, 7), (6, 7)]
[(2, 4), (3, 4)]
[(2, 4), (4, 5)]
[(3, 4), (3, 5), (4, 5)]
[(3, 4), (3, 6)]
[(3, 5), (3, 6), (5, 6)]
[(3, 6), (6, 7)]
[(4, 5), (5, 6)]
[(5, 6), (6, 7)]

2 个回答

2

对于那些和我一样遇到同样问题的人,尤其是节点太多的情况,这里有一些简单的改进建议,参考了@Hooked的回答(虽然@Hooked在评论中提到还有更好的解决方案,这里只是给那些和我有相同困扰的人提供一个快速的解决办法)

1) igraph的性能比networkx要好很多

2) 我们可以只关注一个节点的邻居,这样可以去掉大部分不必要的组合

举个例子,如果我们在更大的network中寻找一个motif(这两个都是igraph对象)

    motif_rank = max(max(motif.shortest_paths_dijkstra()))
    result = collections.OrderedDict.fromkeys(network.vs['label'], 0)

    for node in self.network.vs:
        # Get relevant nodes around node of interest that might create the motif of interest
        nodes_to_expand = {node}
        for rank in range(motif_rank):
            nodes_expanded = nodes_to_expand
            for node_to_expand in nodes_to_expand:
                nodes_expanded = set.union(nodes_expanded, set(node_to_expand.neighbors()))
            nodes_to_expand = nodes_expanded

        # Look at all combinations
        for sub_nodes in itertools.combinations(nodes_to_expand, motif.vcount()):
            subg = network.subgraph(sub_nodes)
            if subg.is_connected() and subg.isomorphic(motif):
                result[node['label']] = result[node['label']]+1
13

这段话的意思是,你想找出和某个target(目标图)匹配的所有子图,你需要先定义这个目标图。最简单的方法就是遍历所有节点的组合,找出那些相连的节点,然后检查它们是否是同构的。这里不太清楚你是想找网络模式(network motif)还是图形小块(graphlet)。在图形小块中,原始图中的所有边都必须存在,这样的话就会把3-4-5从你的目标中排除掉。这个方法是用来找图形小块的,如果你想找网络模式,就需要检查每个组合是否存在诱导子图(以及有多少个!)。

import networkx as nx

g = nx.Graph()
g.add_edge(1,2);g.add_edge(1,3)
g.add_edge(1,7);g.add_edge(2,4)
g.add_edge(3,4);g.add_edge(3,5)
g.add_edge(3,6);g.add_edge(4,5)
g.add_edge(5,6);g.add_edge(6,7)

import itertools

target = nx.Graph()
target.add_edge(1,2)
target.add_edge(2,3)

for sub_nodes in itertools.combinations(g.nodes(),len(target.nodes())):
    subg = g.subgraph(sub_nodes)
    if nx.is_connected(subg) and nx.is_isomorphic(subg, target):
        print subg.edges()

对我来说,这样可以找到边集的匹配:

[(1, 2), (1, 3)]
[(1, 2), (2, 4)]
[(1, 2), (1, 7)]
[(1, 3), (3, 4)]
[(1, 3), (3, 5)]
[(1, 3), (3, 6)]
[(1, 3), (1, 7)]
[(1, 7), (6, 7)]
[(2, 4), (3, 4)]
[(2, 4), (4, 5)]
[(3, 4), (3, 6)]
[(3, 6), (6, 7)]
[(4, 5), (5, 6)]
[(5, 6), (6, 7)]

你的例子在这里列出。

撰写回答