Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在python中有效地计算无向图中的三元组普查_Python_Networkx_Graph Theory_Network Analysis - Fatal编程技术网

如何在python中有效地计算无向图中的三元组普查

如何在python中有效地计算无向图中的三元组普查,python,networkx,graph-theory,network-analysis,Python,Networkx,Graph Theory,Network Analysis,我正在为我的无向网络计算黑社会普查,如下所示 import networkx as nx G = nx.Graph() G.add_edges_from( [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'), ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')]) from itertools import combinations #print(len(list(c

我正在为我的无向网络计算
黑社会普查
,如下所示

import networkx as nx
G = nx.Graph()
G.add_edges_from(
    [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'),
     ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')])

from itertools import combinations
#print(len(list(combinations(G.nodes, 3))))

triad_class = {}
for nodes in combinations(G.nodes, 3):
    n_edges = G.subgraph(nodes).number_of_edges()
    triad_class.setdefault(n_edges, []).append(nodes)
print(triad_class)
它适用于小型网络。但是,现在我有一个更大的网络,大约有4000-8000个节点。当我尝试在1000个节点的网络上运行现有代码时,运行需要几天时间。有没有更有效的方法

我目前的网络基本上是稀疏的。i、 e.节点之间只有很少的连接。在这种情况下,我是否可以保留未连接的节点,先进行计算,然后将未连接的节点添加到输出中

我也很高兴在不计算每一个组合的情况下得到近似的答案

三合会普查示例:

Triad census将Triad(3个节点)划分为下图所示的四个类别

例如,考虑下面的网络。

这四个阶层的三合会普查包括:

{3: [('A', 'B', 'C')], 
2: [('A', 'B', 'D'), ('B', 'C', 'D'), ('B', 'D', 'E')], 
1: [('A', 'B', 'E'), ('A', 'B', 'F'), ('A', 'B', 'G'), ('A', 'C', 'D'), ('A', 'C', 'E'), ('A', 'C', 'F'), ('A', 'C', 'G'), ('A', 'D', 'E'), ('A', 'F', 'G'), ('B', 'C', 'E'), ('B', 'C', 'F'), ('B', 'C', 'G'), ('B', 'D', 'F'), ('B', 'D', 'G'), ('B', 'F', 'G'), ('C', 'D', 'E'), ('C', 'F', 'G'), ('D', 'E', 'F'), ('D', 'E', 'G'), ('D', 'F', 'G'), ('E', 'F', 'G')], 
0: [('A', 'D', 'F'), ('A', 'D', 'G'), ('A', 'E', 'F'), ('A', 'E', 'G'), ('B', 'E', 'F'), ('B', 'E', 'G'), ('C', 'D', 'F'), ('C', 'D', 'G'), ('C', 'E', 'F'), ('C', 'E', 'G')]}
如果需要,我很乐意提供更多细节

编辑:

我能够通过注释行
#print(len(列表(组合(G.nodes,3))
来解决
内存错误。然而,我的程序仍然很慢,即使有1000个节点的网络,也需要几天才能运行。我正在寻找一种在python中实现这一点的更有效的方法

我不局限于
networkx
,也乐于接受使用其他库和语言的答案。

像往常一样,我很乐意根据需要提供更多细节

  • 当您试图将所有组合转换为列表时,程序很可能会崩溃:
    print(len(list(组合(G.nodes,3)))
    。永远不要这样做,因为
    组合
    返回的迭代器消耗少量内存,但列表很容易消耗千兆字节的内存

  • 如果您有稀疏图,则在以下位置查找空间坐标轴更为合理:
    nx.connected\u components(G)

  • Networkx有子模块,但看起来不适合您。我已经修改了networkx.algorithms.triads代码以返回空间坐标轴,而不是它们的计数。你可以找到它。注意,它使用有向图。如果要将其用于无向图,应首先将其转换为有向图


  • 让我们核对一下数字。设n为顶点数,e为边数

    0个三元组位于O(n^3)中

    1个三和弦在O(e*n)中

    O(e)中有2+3个三和弦

    要获得2+3三元组,请执行以下操作:

    For every node a:
       For every neighbor of a b:
          For every neighbor of b c:
            if a and c are connected, [a b c] is a 3 triad
            else [a b c] is a 2 triad
       remove a from list of nodes (to avoid duplicate triads)
    
    
    下一步取决于目标是什么。如果只需要1和0个三元组,那么这就足够了:

    说明:

    1个空间坐标轴都是连接的节点+1个未连接的节点,因此我们通过计算连接节点的数量+1个其他节点来获得该数量,并减去其他节点连接的情况(2和3个空间坐标轴)

    0空间坐标轴只是所有节点的组合减去其他空间坐标轴

    如果你真的需要列出三元组,那你就太不走运了,因为无论你做什么,列出0三元组都是在O(n^3)中,一旦图形变大,你就会被杀死


    上述2+3三元组的算法是O(e*max(#neighbories)),其他部分是O(e+n),用于计算节点和边。比O(n^3)好得多,您需要明确列出0个三元组。列出1个三元组仍然可以在O(e*n)中完成。

    想法很简单:我不直接处理图形,而是使用邻接矩阵。我认为这样会更有效率,而且似乎我是对的

    在邻接矩阵中,A1表示两个节点之间有一条边,例如,第一行可以被读取为“a和B以及C之间存在链接”

    从那里我查看了你的四种类型,发现如下:

    • 对于类型3,N1和N2、N1和N3之间以及N2和N3之间必须有边缘。在邻接矩阵中,我们可以通过遍历每一行(其中每一行表示一个节点及其连接,这是N1)并找到它连接到的节点(这是N2)来找到它。然后,在N2行中,我们检查所有连接的节点(这是N3),并在N1行中保留有正条目的节点。例如“A,B,C”,A与B有连接。B与C有连接,A也与C有连接

    • 对于类型2,其工作原理与类型3几乎相同。除了现在,我们想在N1行的N3列中找到一个0。这方面的一个例子是“A,B,D”。A与B有连接,B在D列中有1,但A没有

    • 对于类型1,我们只需查看N2行,并找到N1行和N2行都具有0的所有列

    • 最后,对于类型0,请查看N1行中条目为0的所有列,然后检查这些行,并查找所有具有0的列

    这段代码应该适合你。对于1000个节点,我花了大约7分钟的时间(在一台配备i7-8565U CPU的机器上),这仍然相对较慢,但与当前运行解决方案所需的几天相比,相差甚远。我已经从您的图片中包括了示例,以便您可以验证结果。代码生成的图形与下面的示例不同。代码中的示例图和邻接矩阵都引用了您包含的图片

    具有1000个节点的示例使用。1000是节点数,0.1是创建边的概率,种子只是为了一致性。我已经设置了创建边的概率,因为你提到了你的图是稀疏的

    :“如果您想要纯Python邻接矩阵表示,请尝试networkx.convert.to_dict_of_dicts,它将返回一个字典字典格式,可以作为稀疏矩阵进行寻址。”

    字典结构有
    M
    字典(=行),最多有
    M个import time
    
    import networkx as nx
    
    
    def triads(m):
        out = {0: set(), 1: set(), 2: set(), 3: set()}
        nodes = list(m.keys())
        for i, (n1, row) in enumerate(m.items()):
            print(f"--> Row {i + 1} of {len(m.items())} <--")
            # get all the connected nodes = existing keys
            for n2 in row.keys():
                # iterate over row of connected node
                for n3 in m[n2]:
                    # n1 exists in this row, all 3 nodes are connected to each other = type 3
                    if n3 in row:
                        if len({n1, n2, n3}) == 3:
                            t = tuple(sorted((n1, n2, n3)))
                            out[3].add(t)
                    # n2 is connected to n1 and n3 but not n1 to n3 = type 2
                    else:
                        if len({n1, n2, n3}) == 3:
                            t = tuple(sorted((n1, n2, n3)))
                            out[2].add(t)
                # n1 and n2 are connected, get all nodes not connected to either = type 1
                for n3 in nodes:
                    if n3 not in row and n3 not in m[n2]:
                        if len({n1, n2, n3}) == 3:
                            t = tuple(sorted((n1, n2, n3)))
                            out[1].add(t)
            for j, n2 in enumerate(nodes):
                if n2 not in row:
                    # n2 not connected to n1
                    for n3 in nodes[j+1:]:
                        if n3 not in row and n3 not in m[n2]:
                            # n3 is not connected to n1 or n2 = type 0
                            if len({n1, n2, n3}) == 3:
                                t = tuple(sorted((n1, n2, n3)))
                                out[0].add(t)
        return out
    
    
    if __name__ == "__main__":
        g = nx.Graph()
        g.add_edges_from(
            [("E", "D"), ("G", "F"), ("D", "B"), ("B", "A"), ("B", "C"), ("A", "C")]
        )
        _m = nx.convert.to_dict_of_dicts(g)
        _out = triads(_m)
        print(_out)
    
        start = time.time()
        g = nx.generators.fast_gnp_random_graph(1000, 0.1, seed=42)
        _m = nx.convert.to_dict_of_dicts(g)
        _out = triads(_m)
        end = time.time() - start
        print(end)
    
    import networkx as nx
    from time import sleep
    from itertools import combinations
    
    
    G = nx.Graph()
    arr=[]
    for i in range(1000):
        arr.append(str(i))
    
    for i,j in combinations(arr, 2):
        G.add_edges_from([(i,j)])
    
    #print(len(list(combinations(G.nodes, 3))))
    triad_class = [[],[],[],[]]
    
    for nodes in combinations(G.subgraph(arr).nodes, 3):
                n_edges = G.subgraph(nodes).number_of_edges()
                triad_class[n_edges].append(nodes)
    
    
    print(triad_class)