Networkx图表删除了计算级别顺序的冗余路径

时间:2016-12-24 07:46:09

标签: networkx

从网络x有向图的data set考虑​​以下图形结构。将上述数据集转换为树时:

enter image description here

拓扑排序按级别顺序给出以下输出(或多或少,这是我要查找的),但不提供有关每个节点对应的每个级别的信息。例如:n0:级别0,n2:级别1和n3:级别1等等。

print(nx.topological_sort(G))
['n2', 'n1', 'n0', 'n3', 'n4', 'n5', 'n6', 'n7', 'n8', 'n9', 'n24', 'n27', 'n21', 'n23', 'n50', 'n15', 'n14', 'n16', 'n17', 'n25', 'n18', 'n19', 'n42', 'n28', 'n38', 'n30', 'n31', 'n32', 'n39', 'n33', 'n34', 'n35', 'n36', 'n37', 'n49', 'n41', 'n40', 'n43', 'n44', 'n29', 'n22', 'n20', 'n26', 'n45', 'n48', 'n46', 'n47', 'n51', 'n54', 'n52', 'n53', 'n11', 'n10', 'n13', 'n12', 'n55']

因此,我进一步使用nextworkx.single_source_shortest_path_length()处理数据集,并根据级别对订单进行排序。由于在图中存在多个边缘,因此单个源最短路径输出不是非常准确。

from operator import itemgetter
nd = nx.single_source_shortest_path_length(G,'n0')
sorted(nd.items(), key=itemgetter(1))
[('n0', 0),
 ('n12', 1),
 ('n13', 1),
 ...
 ('n4', 1),
 ('n5', 1),
 ('n6', 1),
 ('n7', 1)]

为了解决这个问题,我试图找出一种基于以下方法的解决方案:
1.通过删除冗余路径并使用single_source_shortest_path()计算级别顺序。为了实现这一点,我可能必须删除冗余路径,以便每个节点只有一条路径,直到根(n0),通过它父。冗余路径的所有路径除了在到根节点(n0)的路上访问附近节点(父节点)的路径之外。因此,节点只能有一条到根路径(不一定是最短路径)。

例如:如果节点(n221)与父节点(n22)有边缘,而另一边节点是祖父节点(n或n2),则删除所有边缘{s}到祖父节点(删除边缘n221 --- > n),如果父(n22)具有祖父母的边(n22 ---> n)。

  1. 我可以获得拓扑排序输出。使用输出,我可以使用nx.topological_sort(G)nx.bfs_successors(G, 'n0')重建更简单的树,类似于this question
  2. 中的实现

    最终希望获得以下结果以从根目录n0开始迭代每个级别:

    Levels: nodes   
    1: n0
    2: n3, n21
    3: n4
    4: n5
    6: n7, n15 ...
    7: ...
    

    为了达到正确的结果,我在这里失去了什么,我怎样才能达到预期的行为?

    我正在处理具有~1.5K节点的非常大的数据集,因此这里采用了一个简单的例子,而不是呈现完整的数据集。

2 个答案:

答案 0 :(得分:2)

当叶子同时存在时,您似乎想要从叶节点(已定义here)中删除任何边到根节点:

  1. 到根节点的边缘
  2. 根目录的替代路径
  3. 上面的G图表有点凌乱,与您的图片'完全匹配。描写。 (例如,n511未显示)

    import matplotlib as plt
    import networkx as nx
    
    pos=nx.drawing.nx_pydot.pydot_layout(G, prog='dot')
    nx.draw(G, pos=pos, with_labels=True)
    

    enter image description here

    如果我理解正确,这个解决方案可能有所帮助。它遍历叶子并检查叶子是否具有到根节点的> 1路径。嵌套if条件检查leaf与根节点'n'

    之间的直接边缘
    removed = []
    for leaf in (x for x in G.nodes_iter() if G.out_degree(x)==0 and G.in_degree(x)>=1):
        if sum(1 for _ in nx.all_simple_paths(G, 'n', leaf)) >1: # equivalent to len(generator)
                if G.has_edge('n',leaf):
                    removed.append(('n', leaf)) # shows edges removed
                    G.remove_edge('n', leaf)
    
    print(removed)
    [('n', 'n221'), ('n', 'n51'), ('n', 'n131')]
    

    它清理图表,如果节点'n'不是真正的根,这可能会中断。

    pos=nx.drawing.nx_pydot.pydot_layout(G, prog='dot')
    nx.draw(G, pos=pos, with_labels=True)
    

    enter image description here

    修改

    这是我的最后一次尝试,可能应该将此留给更有经验的人回答。尝试迭代节点并提取从根到节点的最长路径。必须有更好的方法来执行此操作,也许有人可以推荐。

    假设G是根据您在评论中提供的链接中的代码创建的。

    G1 = nx.DiGraph()
    for n in nodes:
        if n == 'n0': # skip n0
            continue
        if not nx.has_path(G, 'n0', n): #n1 and n2 are disconnected from n0
            lpath= max(list(nx.all_simple_paths(G, n, 'n55')), key=len)
            G1.add_path(lpath)
            continue
        lpath= max(list(nx.all_simple_paths(G, 'n0', n)), key=len)
        G1.add_path(lpath)
    
    #levels
    sorted(nx.shortest_path_length(G1, 'n0').items(), key=operator.itemgetter(1)) # omits n1, n2
    
    [('n0', 0),
     ('n21', 1),
     ('n3', 1),
     ('n4', 2),
     ('n5', 3),
     ('n15', 4),
     ('n24', 4),
     ('n6', 4),
     ('n7', 4),
     ('n8', 5),
     ('n12', 6),
     (...
    
    
    plt.figure(figsize=(20,12))
    pos=nx.drawing.nx_pydot.pydot_layout(G1, prog='dot')
    nx.draw(G1, pos=pos, with_labels=True)
    

    enter image description here

答案 1 :(得分:1)

我不确定我理解你的问题,但我认为你想要的只是从根到图中任何节点只有一条路径。

如果这是您的要求,那么实现它的唯一方法就是使用树。如果我理解正确,您还希望所有剩余路径都是根目录中最短的路径,在这种情况下,您正在寻找的树就是BFS树。

你可以在NetworkX中得到它:

import networkx as nx

G = nx.DiGraph()
G.add_edges_from([('n', 'n1'), ('n', 'n2'), ('n', 'n3'), ('n', 'n4'), ('n', 'n5')])
G.add_edges_from([('n4', 'n41'), ('n1', 'n11'), ('n1', 'n12'), ('n1', 'n13'), ('n5', 'n51'), ('n12', 'n131')])
G.add_edges_from([('n2', 'n21'), ('n2', 'n22'), ('n', 'n221'), ('n', 'n51')])
G.add_edges_from([('n13', 'n131'), ('n22', 'n221'), ('n', 'n131'), ('n', 'n221'), ('n', 'n511')])

G = nx.bfs_tree(G, 'n')

nx.draw(G, with_labels=True)

产生类似这样的东西:

BFS Tree of the given graph