【问题标题】:Networkx never finishes calculating Betweenness centrality for 2 mil nodesNetworkx 从未完成计算 200 万个节点的中介中心性
【发布时间】:2015-09-08 19:13:31
【问题描述】:

我有一个简单的 Twitter 用户图,其中包含大约 200 万个节点和 500 万条边。我正在尝试使用 Centrality。但是,计算需要很长时间(超过一个小时)。我不认为我的图表非常大,所以我猜我的代码可能有问题。

这是我的代码。

%matplotlib inline
import pymongo
import networkx as nx
import time
import itertools

from multiprocessing import Pool
from pymongo import MongoClient

from sweepy.get_config import get_config

config = get_config()

MONGO_URL = config.get('MONGO_URL')
MONGO_PORT = config.get('MONGO_PORT')
MONGO_USERNAME = config.get('MONGO_USERNAME')
MONGO_PASSWORD = config.get('MONGO_PASSWORD')

client = MongoClient(MONGO_URL, int(MONGO_PORT))

db = client.tweets
db.authenticate(MONGO_USERNAME, MONGO_PASSWORD)

users = db.users
graph  = nx.DiGraph()


for user in users.find():
    graph.add_node(user['id_str'])
    for friend_id in user['friends_ids']:
        if not friend_id in graph:
            graph.add_node(friend_id)
        graph.add_edge(user['id_str'], friend_id)

数据在 MongoDB 中。这是数据示例。

{
    "_id" : ObjectId("55e1e425dd232e5962bdfbdf"),
    "id_str" : "246483486",
    ...
    "friends_ids" : [ 
         // a bunch of ids
    ]
}

我尝试使用中间中心性并行来加速,但它仍然非常慢。 https://networkx.github.io/documentation/latest/examples/advanced/parallel_betweenness.html

"""
Example of parallel implementation of betweenness centrality using the
multiprocessing module from Python Standard Library.

The function betweenness centrality accepts a bunch of nodes and computes
the contribution of those nodes to the betweenness centrality of the whole
network. Here we divide the network in chunks of nodes and we compute their
contribution to the betweenness centrality of the whole network.
"""
def chunks(l, n):
    """Divide a list of nodes `l` in `n` chunks"""
    l_c = iter(l)
    while 1:
        x = tuple(itertools.islice(l_c, n))
        if not x:
            return
        yield x


def _betmap(G_normalized_weight_sources_tuple):
    """Pool for multiprocess only accepts functions with one argument.
    This function uses a tuple as its only argument. We use a named tuple for
    python 3 compatibility, and then unpack it when we send it to
    `betweenness_centrality_source`
    """
    return nx.betweenness_centrality_source(*G_normalized_weight_sources_tuple)


def betweenness_centrality_parallel(G, processes=None):
    """Parallel betweenness centrality  function"""
    p = Pool(processes=processes)
    node_divisor = len(p._pool)*4
    node_chunks = list(chunks(G.nodes(), int(G.order()/node_divisor)))
    num_chunks = len(node_chunks)
    bt_sc = p.map(_betmap,
                  zip([G]*num_chunks,
                      [True]*num_chunks,
                      [None]*num_chunks,
                      node_chunks))

    # Reduce the partial solutions
    bt_c = bt_sc[0]
    for bt in bt_sc[1:]:
        for n in bt:
            bt_c[n] += bt[n]
    return bt_c



print("Computing betweenness centrality for:")
print(nx.info(graph))
start = time.time()
bt = betweenness_centrality_parallel(graph, 2)
print("\t\tTime: %.4F" % (time.time()-start))
print("\t\tBetweenness centrality for node 0: %.5f" % (bt[0]))

从Mongodb导入networkx的过程比较快,不到一分钟。

【问题讨论】:

  • 你可能会尝试 igraph... 一般来说,它不像 networkx 那样容易使用,但它往往要快得多,特别是对于大型图,并且使用更少的内存。 ..
  • 您可能还想研究 GPU 加速计算,或许可以使用通常用于优化机器学习的库之一,例如用于神经网络计算的库。

标签: python mongodb ipython networkx


【解决方案1】:

TL/DR:中介中心性是一个非常缓慢的计算,因此您可能希望通过考虑myk 节点的子集来使用近似度量,其中myk 比网络中的节点数少得多,但足够大以具有统计意义(NetworkX 有一个选项:betweenness_centrality(G, k=myk)


我一点也不惊讶它需要很长时间。中介中心性是一个缓慢的计算。 networkx 使用的算法是O(VE),其中V 是顶点数,E 是边数。在你的情况下VE = 10^13。我预计导入图表需要O(V+E) 时间,所以如果这需要足够长的时间以至于您可以判断它不是瞬时的,那么O(VE) 将会很痛苦。

如果具有 1% 的节点和 1% 的边(即 20,000 个节点和 50,000 条边)的缩减网络需要时间 X,那么您所需的计算将需要 10000X。如果 X 是一秒,那么新的计算接近 3 小时,我认为这是非常乐观的(参见下面的测试)。因此,在您确定您的代码有问题之前,请在一些较小的网络上运行它并估计您的网络的运行时间。

一个不错的选择是使用近似度量。标准介数度量考虑了每一对节点以及它们之间的路径。 Networkx 提供了一种替代方案,它使用仅k 节点的随机样本,然后在这些k 节点和网络中的所有其他节点之间找到最短路径。我认为这应该可以加快在O(kE) 时间运行

所以你会使用的是

betweenness_centrality(G, k=k)

如果您想限制结果的准确度,可以使用较小的 k 值进行多次调用,确保它们相对接近,然后取平均结果。


这是我对运行时间的一些快速测试,随机图表为 (V,E)=(20,50); (200,500);和 (2000,5000)

import time
for n in [20,200,2000]:
    G=nx.fast_gnp_random_graph(n, 5./n)
    current_time = time.time()
    a=nx.betweenness_centrality(G)
    print time.time()-current_time

>0.00247192382812
>0.133368968964
>15.5196769238

因此,在我的计算机上,处理一个大小为您的 0.1% 的网络需要 15 秒。建立一个和你一样大小的网络大约需要 1500 万秒。那是 1.5*10^7 秒,略低于 pi*10^7 秒的一半。由于 pi*10^7 秒是一年中秒数的一个非常好的近似值,因此我的计算机大约需要 6 个月。

因此您需要使用近似算法运行。

【讨论】:

  • 你知道在 python 中有效逼近 BC 的任何库吗?
猜你喜欢
  • 2019-04-08
  • 1970-01-01
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-10
  • 1970-01-01
  • 2021-02-18
相关资源
最近更新 更多