NetworkX-删除节点并重新连接边缘

时间:2018-11-17 16:47:01

标签: networkx

我在图中有一个节点,它充当一种“临时连接器”节点。我想删除该节点并更新图中的边,以便其所有直接前辈都指向其直接后继。

networkx中是否有内置功能可以执行此操作,还是需要推出自己的解决方案?

示例:

我有一个图1 > 2 > 3。我想删除节点2,最后得到图1 > 3

这是我目前的操作方式:

In [230]: g = nx.DiGraph()

In [231]: g.add_edges_from([(1,2),(2,3)])

In [232]: g.edges()
Out[232]: [(1, 2), (2, 3)]

In [233]: predecessors = g.predecessors(2)

In [234]: successors = g.successors(2)

In [235]: new_edges = [(p,s) for p in predecessors for s in successors]

In [236]: new_edges
Out[236]: [(1, 3)]

In [237]: g.remove_node(2)

In [238]: g.add_edges_from(new_edges)

In [239]: g.nodes()
Out[239]: [1, 3]

In [240]: g.edges()
Out[240]: [(1, 3)]

2 个答案:

答案 0 :(得分:0)

我不知道我的解决方案是否比Ryan所建议的要好,但是我在这里发布了一个函数,因为它试图从不同的角度解决这个问题。他们的关键是,在graph 1 > 2 > 3中,节点2的度数为2(即,有2个边与其连接)。一般而言,从提出的问题的意义上简化图将意味着除去所有具有2级的此类节点。下面的函数正是这样做的。

def simplifyGraph(G):
    ''' Loop over the graph until all nodes of degree 2 have been removed and their incident edges fused '''

    g = G.copy()

    while any(degree==2 for _, degree in g.degree):

        g0 = g.copy() #<- simply changing g itself would cause error `dictionary changed size during iteration` 
        for node, degree in g.degree():
            if degree==2:

                if g.is_directed(): #<-for directed graphs
                    a0,b0 = list(g.in_edges(node))[0]
                    a1,b1 = list(g.out_edges(node))[0]

                else:
                    edges = g.edges(node)
                    edges = list(edges.__iter__())
                    a0,b0 = edges[0]
                    a1,b1 = edges[1]

                e0 = a0 if a0!=node else b0
                e1 = a1 if a1!=node else b1

                g0.remove_node(node)
                g0.add_edge(e0, e1)
        g = g0

    return g

一个例子:

>>> G = nx.DiGraph()
>>> G.add_edges_from([(1,2),(2,3)])
>>> list(G.edges)
[(1, 2), (2, 3)]

>>> g = simplifyGraph(G)
>>> list(g.edges)
[(1, 3)]

答案 1 :(得分:0)

我尝试在一个巨大的复杂 MultiGraph 上使用 mjvaak 的答案,但它不起作用,因为它使用不再存在的节点创建边。我通过简单地从 g0 中取边来修复它。

所以我改变了:

edges = g.edges(node)

用于:

edges = g0.edges(node)

固定代码如下:

def simplifyGraph(G):
''' Loop over the graph until all nodes of degree 2 have been removed and their incident edges fused '''

g = G.copy()

while any(degree==2 for _, degree in g.degree):

    g0 = g.copy() #<- simply changing g itself would cause error `dictionary changed size during iteration` 
    for node, degree in g.degree():
        if degree==2:

            if g.is_directed(): #<-for directed graphs
                a0,b0 = list(g0.in_edges(node))[0]
                a1,b1 = list(g0.out_edges(node))[0]

            else:
                edges = g0.edges(node)
                edges = list(edges.__iter__())
                a0,b0 = edges[0]
                a1,b1 = edges[1]

            e0 = a0 if a0!=node else b0
            e1 = a1 if a1!=node else b1

            g0.remove_node(node)
            g0.add_edge(e0, e1)
    g = g0

return g

感谢 mjkvaak 的解决方案!对于更大的图表,它只需要稍作修改。