【问题标题】:Find improper nodes by rules in networkx?通过networkx中的规则找到不合适的节点?
【发布时间】:2012-08-27 01:22:18
【问题描述】:

全部,

考虑下面的示例“树状”图。

垂直它是一个基于节点“0”的层次结构。 横向上它是一个从级别 1 开始的基于组的结构,组意味着从一个根节点继承的节点

    '''                         
                              +---+       
                              | 0 |                                    Level 0
                              +---+       
                                |
                 +--------------+---------------+         
                 |              |               |           
               +---+          +---+           +---+      
               | 1 |          | 2 |           | 3 |                    Level 1      
               +---+          +---+           +---+      
     +-----+----+        +-----+-----+        +|---+-----+            
     |     |     |        |     |     |        |    |     |           
   +---+ +---+ +---+    +---+ +---+ +---+   +---+ +---+ +---+  
   |11 | |12 | |13 |    |21 | |22 | |23 |   |31 | |32 | |33 |          Level 2 
   +---+ +---+ +---+    +---+ +---+ +---+   +---+ +---+ +---+  
     |     |   / |    /   |      |            |                 
     |     | /   | /      |      |            |  
     |   +---+ +---+    +---+ +---+           |
     |   |121|-|131|    |211| |221|           |                        Level 3                                 
     |   +---+ +---+    +---+ +---+           |
     |           |--------|------|            |
     |-----------|----------------------------|     


 |     Group 0       |       group 1     |      group 2       |
'''

在 Networkx 中创建:

# create it in networkx
import networkx as nx
G = nx.DiGraph()
G.add_edges_from([('0', '1'), ('0', '2'), ('0', '3')])
G.add_edges_from([('1', '11'), ('1', '12'), ('1', '13')])
G.add_edges_from([('2', '21'), ('2', '22'), ('2', '23')])
G.add_edges_from([('3', '31'), ('3', '32'), ('3', '33')])
#
G.add_edges_from([('12', '121'), ('13', '131')])
G.add_edges_from([('12', '121'), ('13', '131')])
G.add_edges_from([('21', '211'), ('22', '221')])
#
G.add_edges_from([('13', '121')])  
G.add_edges_from([('21', '131')])  
G.add_edges_from([('131', '211')])  
G.add_edges_from([('131', '221')])

#
G.add_edges_from([('121', '13')])            # node may not with "in_degree" link only
G.add_edges_from([('131', '21')])            # ditto

#
G.add_edges_from([('131', '31')]) 
G.add_edges_from([('131', '11')])
G.add_edges_from([('11', '131')])

#
G.add_edges_from([('121', '131')])

问题:

如何在图中找出节点和边,以下面的节点为样本:

  1. “121”,在同一组中有多个链接到更高级别? (节点边缘类型“不确定”,可能是 in_degree 或 out_degree 或两者兼而有之,以下问题相同)

  2. “131”,有多个链接到更高级别节点到其他组?

  3. “131”,同组同级节点的链接

  4. “131”,链接到同级节点但在其他组中

  5. “21”,链接到不同组中的低级节点

“Graph”新手并尝试获取示例代码以了解如何使用 networkx 深入挖掘。

非常感谢。

【问题讨论】:

    标签: python graph networkx


    【解决方案1】:

    这样的事情可能会奏效。它使用节点的长度作为级别(必须在代码中注释掉您的级别 0 节点才能使其工作)和节点字符串的第一个元素作为组。我认为这就是您对数据结构的意图。

    # create it in networkx
    import networkx as nx
    G = nx.DiGraph()
    #G.add_edges_from([('0', '1'), ('0', '2'), ('0', '3')])
    G.add_edges_from([('1', '11'), ('1', '12'), ('1', '13')])
    G.add_edges_from([('2', '21'), ('2', '22'), ('2', '23')])
    G.add_edges_from([('3', '31'), ('3', '32'), ('3', '33')])
    #
    G.add_edges_from([('12', '121'), ('13', '131')])
    G.add_edges_from([('12', '121'), ('13', '131')])
    G.add_edges_from([('21', '211'), ('22', '221')])
    #
    G.add_edges_from([('13', '121')])
    G.add_edges_from([('21', '131')])
    G.add_edges_from([('131', '211')])
    G.add_edges_from([('131', '221')])
    
    #
    G.add_edges_from([('121', '13')])            # node may not with "in_degree" link only
    G.add_edges_from([('131', '21')])            # ditto
    
    #
    G.add_edges_from([('131', '31')])
    G.add_edges_from([('131', '11')])
    G.add_edges_from([('11', '131')])
    G.add_edges_from([('121', '131')])
    
    # "121", with more than one link to higher level in same group? (node edge type "unsure", may in_degree or out_degree or both, same in following question)
    
    print "more than one link to higher level in same group"
    for node in G:
        l = len(node)-1 # higher level
        others = [n for n in G.successors(node)+G.predecessors(node)
                  if len(n)==l and n[0]==node[0]]
        if len(others) > 1:
            print node
    
    # "131", with more than one link to higner level nodes to other group?
    print "more than one link to higher level in same group"
    for node in G:
        l = len(node)-1 # higher level
        others = [n for n in G.successors(node)+G.predecessors(node)
                  if len(n)==l and n[0]!=node[0]]
        if len(others) > 1:
            print node
    
    
    # "131", with links to same level nodes in same group
    print "same level, same group"
    for u,v in G.edges():
        if len(u) == len(v):
            if u[0] == v[0]:
                print u
    
    # "131", with links to same level nodes but in other group
    print "same level, other group"
    for u,v in G.edges():
        if len(u) == len(v):
            if u[0] != v[0]:
                print u
    
    
    # "21", with links to lower level nodes in different group
    print "same level, other group"
    for u,v in G.edges():
        if len(u) == len(v)-1:
            if u[0] != v[0]:
                print u
    

    【讨论】:

    • Aric,感谢您对 Networkx 的回答。但我仍然认为使用len(node) 与 Michale 的帮助功能相同 - 它也依赖节点“名称”来区分“节点级别”,是否可以通过给定一个“根节点”来做到这一点?例如,通过从节点 X 到该“根节点”的列表路径来判断节点 X 是(是)哪个可能级别?
    • 是的,例如,您可以设置 levels = nx.shortest_path_length(G,'0') 来获取节点和级别的 Python 字典。您可以使用它来代替字符串长度技术。
    【解决方案2】:

    首先,您应该以某种方式定义节点所在的组或级别,因为它没有在图表 istelf 中定义,因为额外的边会破坏树结构。 我只是按照你的命名模式编写了这些帮助函数来将给定的名称转换为级别/组:

    def get_group(node):
        if node == '0':
            return 1
        return int(node[0])-1
    
    def get_level(node):
        if node == '0':
            return 0
        return len(node)
    
    def equal_group(a,b):
        return get_group(a) == get_group(b)
    
    def lower_level(a,b):
        return get_level(a) < get_level(b)
    
    def equal_level(a,b):
        return get_level(a) == get_level(b)
    

    然后你可以根据你的规范去过滤节点:

    def filter_q1(node):
        k = len([predecessor for predecessor in G.predecessors_iter(node) if equal_group(node, predecessor) and lower_level(predecessor, node)] )
        return k > 1
    q1_result = filter(filter_q1, G)
    print 'Q1:', q1_result
    
    
    def filter_q2(node):
        k = len([predecessor for predecessor in G.predecessors_iter(node) if lower_level(predecessor, node)])
        return k > 1
    q2_result = filter(filter_q2, G)
    print 'Q2:', q2_result
    
    
    def filter_q3(node):
        k = len([neighbour for neighbour in G.neighbors_iter(node) if equal_level(node, neighbour) and equal_group(node, neighbour)])
        return k > 0
    q3_result = filter(filter_q3, G)
    print 'Q3:', q3_result
    
    
    def filter_q4(node):
        k = len([neighbour for neighbour in G.neighbors_iter(node) if equal_level(node, neighbour)])
        return k > 0
    q4_result = filter(filter_q4, G)
    print 'Q4:', q4_result
    
    
    def filter_q5(node):
        k = len([neighbour for neighbour in G.neighbors_iter(node) if not equal_group(node, neighbour)])
        return k > 0
    q5_result = filter(filter_q5, G)
    print 'Q5:', q5_result
    

    结果如下所示:

    >>>Q1: ['131', '121']
    >>>Q2: ['131', '121']
    >>>Q3: ['121']
    >>>Q4: ['131', '121']
    >>>Q5: ['21', '131', '0']
    

    一般来说,您可以像这样找到不需要的边缘:

    def is_bad_edge(edge):
        a, b = edge
        if not equal_group(a, b):
            return True
        if not lower_level(a, b):
            return True
        return False
    bad_edges = filter(is_bad_edge, G.edges_iter())
    print 'Bad edges:', bad_edges 
    

    结果如下:

    >>>Bad edges: [('21', '131'), ('131', '11'), ('131', '31'), ('131', '21'), ('131', '221'), ('131', '211'), ('121', '13'), ('121', '131'), ('0', '1'), ('0', '3')]
    

    正如您所看到的,源自0 的边在其中,因为它被归类为第 1 组,但节点 1 和节点 3 不是。根据您对节点0 的分类方式,您可以调整函数以包含或排除根节点。

    【讨论】:

    • Michael,谢谢你的帮助,但是,你能解释一下你改变的边缘吗 'G.add_edges_from([('12', '121'), ('12', ' 131')])' ,在图 12 和 131 中应该没有直接的边,此外,除了节点之外,是否可以列出不需要的边?谢谢。
    • 好的,但至少该行是多余的,因为它与上面的行相同。我添加了一些关于边缘的内容并删除了更正。
    • Michael,谢谢,我刚刚意识到您提供的帮助功能是基于节点名称的,对吧?这里的节点 0 由于它的名称而被帮助功能自动识别为根,如果我从其他方向查看图形怎么样,例如从右到左查看,例如节点 33 作为根?是否可能与帮助功能名称无关?我认为这是我对你的灵感感到困惑的一个关键部分。
    • 主要问题是,您需要对构成“组”和“级别”的内容有一个合理的定义。如果你有一个合适的树,这将相当容易,但如果你可以在那里有任意边缘,它会变得更加复杂。例如。您如何将节点 131 分类为组 1 或组 2?它在两者都有父母,那么哪个是错误的边缘? 131 真的是 121 的孩子,因此是 4 级吗?您可能想要寻找更一般的东西,例如检查图形是否是树并查找树结构的违规行为。
    • 哦,如果您将节点 33 设为根,那么无论如何整个事情都会分崩离析,因为边缘的方向都是错误的。 (节点 33 没有子节点)
    猜你喜欢
    • 2019-06-22
    • 2011-05-27
    • 1970-01-01
    • 2016-04-23
    • 1970-01-01
    • 2016-04-12
    • 2019-06-17
    • 1970-01-01
    • 2014-07-18
    相关资源
    最近更新 更多