【问题标题】:efficient projection of a bipartite graph in python (using networkx)python中二分图的有效投影(使用networkx)
【发布时间】:2011-11-21 02:49:02
【问题描述】:

使用 networkx 模块,我在 Python 3.2 下进行了一些网络分析,其中我需要将二分图(链接到其牢房的囚犯:在下面的代码中输入图 B)投影到子图(将狱友相互链接如果两者在同一个单元格中有重叠的咒语:使用定义图 B 的同居节点的集合节点的输入,生成输出图 G)。我不需要特殊的算法来提出任何或最佳匹配,我只需要收集满足某些条件的所有链接。因此,我发现的其他 SO 帖子并不真正适用。但是:

随着我提供越来越多的数据,我当前的代码正在崩溃(RAM、交换和 CPU 方面)。如果您发现使用 5 层循环简化以下代码的方法,请告诉我。我不确定是否需要任何有关 networkx 的知识,或者我的边缘属性标签的详细信息是否相关。谢谢!

def time_overlap_projected_graph_parallel(B, nodes):
    G=nx.MultiGraph()
    G.add_nodes_from((n,B.node[n]) for n in nodes)
    for u in nodes:
        unbrs = set(B[u])
        nbrs2 = set((n for nbr in unbrs for n in B[nbr])) - set([u])
        for v in nbrs2:
            for mutual_cell in set(B[u]) & set(B[v]):
                for uspell in B.get_edge_data(u,mutual_cell).values():
                    ustart = uspell[1]
                    uend = uspell[2]
                    for vspell in B.get_edge_data(v,mutual_cell).values():
                        vstart = vspell[1]
                        vend = vspell[2]
                        if uend > vstart and vend > ustart:
                            ostart = max(ustart,vstart)
                            oend = min(uend,vend)
                            olen = (oend-ostart+1)/86400
                            ocell = mutual_cell
                            if (v not in G[u] or ostart not in [ edict[1] for edict in G[u][v].values() ]):
                                G.add_edges_from([(u,v,{0: olen,1: ostart,2: oend,3: ocell})])
    return G

【问题讨论】:

  • 你能澄清更多吗?我猜B是原始图,那么什么是节点?而且我不确定我是否理解你想要什么。你有一个牢房和囚犯的二分图。那你想要一张什么图?只是犯人?如果它们在同一个单元格中,则连接?
  • 谢谢,Avaris,您理解正确,但我也会澄清我的问题。
  • 好的。术语“子图”让我震惊,因为从技术上讲,新图不会是子图。在这种情况下,为什么不直接遍历单元格并在新图中连接单元格的邻居?
  • 循环在 python 中效率不高 (wiki.python.org/moin/PythonSpeed/PerformanceTips#Loops)。如果您的 2 个内部循环变大,它可能确实会变得非常慢。你循环的东西的典型尺寸是多少?
  • 试图从代码中理解(如果我错了,请纠正我):节点 = 囚犯,u = 第一个囚犯,unbrs = 你所在的牢房,nbrs2 = 留在 unbrs 的所有囚犯,v = 另一个囚犯,mutual_cell = 他们共享的牢房。

标签: python performance loops python-3.x networkx


【解决方案1】:

我猜现在可以使用二分图了。喜欢

import networkx as nx
from networkx.algorithms import bipartite

B.add_nodes_from(inmates_list, bipartite=0)
B.add_nodes_from(cells_list, bipartite=1)

inmates = set(n for n,d in B.nodes(data=True) if d['bipartite']==0)
cells = = set(B) - inmates
G = bipartite.projected_graph(B, inmates)

(http://networkx.lanl.gov/reference/algorithms.bipartite.html)

【讨论】:

  • 在 NetworkX 2.0 中,您可以执行类似 inmates = {n for n, is_inmate in B.nodes(data='bipartite') if is_inmate} 的操作,这会更好一些(假设您颠倒了 bipartite 属性值 1 和 0)。
【解决方案2】:

这是我的看法。根据每个牢房的平均囚犯人数,它可能会提高性能。如果您有更好的方法来获取单元格(例如节点属性?),请替换

cells = [n for n in B.nodes() if n[0] not in nodes]

这样(这里我假设节点是所有囚犯的列表)。

from itertools import combinations

def time_overlap_projected_graph_parallel(B, nodes):
    G=nx.MultiGraph()
    G.add_nodes_from((n,B.node[n]) for n in nodes)
    cells = [n for n in B.nodes() if n[0] not in nodes]
    for cell in cells:
        for u,v in combinations(B[cell],2):
            for uspell in B.get_edge_data(u,cell).values():
                ustart = uspell[1]
                uend = uspell[2]
                for vspell in B.get_edge_data(v,cell).values():
                    vstart = vspell[1]
                    vend = vspell[2]
                    if uend > vstart and vend > ustart:
                        ostart = max(ustart,vstart)
                        oend = min(uend,vend)
                        olen = (oend-ostart+1)/86400
                        ocell = cell
                        if (v not in G[u] or ostart not in [ edict[1] for edict in G[u][v].values() ]):
                            G.add_edge(u,v,{0: olen,1: ostart,2: oend,3: ocell})
    return G

【讨论】:

    【解决方案3】:

    我发布此答案是为了建议一些改进。我将假设您的二分图不是多图,而是普通的nx.Graph。我将B 更改为bi,将G 更改为uni,因为按照惯例,大写名称是为类保留的。顺便说一句,如果咒语在同一时间开始和结束呢?

    def time_overlap_projected_graph_parallel(bi, nodes):
        uni = nx.MultiGraph()
        for u in nodes: #inmate
            uni.add_node(u) # do this to prevent iterating nodes twice
            u_adj = bi.adj[u] # bi.adj is a dict of dicts
            for (w, uw_attr) in u_adj.iteritems(): # cell
                w_adj = bi.adj[w]
                for (v, wv_attr) in w_adj.iteritems():#cellmate
                    if v == u:
                        continue
                    elif uni.has_edge(u, v): # avoid computing twice
                        continue
                    for uspell in uw_attr.itervalues():
                        ustart = uspell[1]
                        uend = uspell[2]
                        for vspell in wv_attr.itervalues():
                            vstart = vspell[1]
                            vend = vspell[2]
                            if uend > vstart and vend > ustart:
                                ostart = max(ustart, vstart)
                                oend = min(uend, vend)
                                olen = (oend - ostart + 1) / 86400 # this assumes floats or Python 3 otherwise will be 0
                                ocell = w
                                # I would change this to uni.add_edge(u, v, length=olen, start=ostart, end=oend, cell=ocell)
                                # or to uni.add_edge(u, v, spell=[olen, ostart, oend, ocell])
                                uni.add_edge(u, v, **{0: olen, 1: ostart, 2: oend, 3: ocell})
        return uni
    

    【讨论】:

    • 谢谢,我现在无法重新运行它来检查它的速度有多快。为什么您期望它会更快?关于咒语:我可以放弃以错误开头的咒语。
    • 这应该更快的主要原因是检查uni.has_edge(u, v)。由于您正在遍历所有节点,因此当您达到逆 uni.had_edge(v, u) 时,这将避免很多步骤,这将已经被计算出来。您的代码还检查一个拼写的交集是否已经存在于一个列表中,该列表是一个O(n) 操作。不确定这些列表有多长。考虑到这一点,可以改进整个法术计算。我会相应地编辑。总的来说,对于非常大的网络,networkx 可能不是正确的工具。
    • @László 我在谈论这个案子if uend >= vstart and vend >= ustart
    • 谢谢,我认为这只会重复计算相同的东西,不是吗?
    【解决方案4】:

    考虑修改后的代码,它可能会做同样的事情,但使用迭代器(虽然我也修改了一些与 networkx 相关的函数/方法调用 --- 但我仍在检查我是否破坏了某些东西):

    def time_overlap_projected_graph_parallel(B, nodes):
        G=nx.MultiGraph()
        G.add_nodes_from(nodes)
        for u in G.nodes_iter():#inmate
            for w in B.neighbors_iter(u):#cell
                for v in B.neighbors_iter(w):#cellmate
                    if v == u:
                        continue
                    for uspell in B[u][w].values():
                        ustart = uspell[1]
                        uend = uspell[2]
                        for vspell in B[v][w].values():
                            vstart = vspell[1]
                            vend = vspell[2]
                            if uend > vstart and vend > ustart:
                                ostart = max(ustart,vstart)
                                oend = min(uend,vend)
                                olen = (oend-ostart+1)/86400
                                ocell = w
                                if (v not in G[u] or ostart not in [ edict[1] for edict in G[u][v].values() ]):
                                    G.add_edges_from([(u,v,{0: olen,1: ostart,2: oend,3: ocell})])
        return G
    

    【讨论】:

      猜你喜欢
      • 2013-04-06
      • 1970-01-01
      • 2020-01-14
      • 2015-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      相关资源
      最近更新 更多