【问题标题】:Efficient way to read and write a Networkx Graph读取和写入 Networkx Graph 的有效方法
【发布时间】:2020-08-18 11:43:13
【问题描述】:

对于一个开源项目,我正在尝试使用 NetworkX 来找到 Graph 的吸引子(称为 State Transition Graph)。问题是对于近 2**33 个循环,具有多种输入的函数返回一个元组列表(近 5000 个元组),其中每个元组包含需要馈送到 networkx 图的边。如下:

def BigGraph:
    #Do some computations
    G = nx.DiGraph()
    for i in range(2**33):
        #Do some computations
        edges = func(different initial conditions)
        G.add_edges_from(edges)

如前所述,由于边数增长得更快,而且 NetworkX 图在 RAM 上占用了大量内存,我尝试如下连续读取和写入 pickle 文件:

def BigGraph:
    #Do some computations
    G = nx.DiGraph()
    nx.write_gpickle(G, 'graph.gpickle')
    for i in range(2**33):
        #Do some computations
        edges = func(different initial conditions)
        G = nx.read_gpickle('graph.gpickle')
        G.add_edges_from(edges)
        nx.write_gpickle(G, 'graph.gpickle')

在此之后,我意识到随着边缘呈指数增长,对泡菜的读写会影响我大量的时间和记忆。我已经尝试过here 的建议,但正如那个问题中提到的,我不需要经常使用 Graph。最终,如果可能的话,我需要做的就是在复杂度为 O(1) 的 networkx 图中添加很多边。

无论如何我都可以这样做,这样可以节省大量时间并且不会对我的记忆造成问题(我有 8 GB 的 RAM)。我愿意使用任何外部库,只要它们是免费的并且可以有效地完成我打算做的事情。

编辑:我想知道是否有一种方法可以使用 memmap 将我的图表存储在我的硬盘上并找到图表的吸引组件。使用 NetworkX 对我来说是必须的。

【问题讨论】:

  • 我不明白为什么如果你继续阅读酸洗会避免内存问题。
  • 节点是什么数据类型?整数?如果是字符串,那么使用整数可以立即节省内存。
  • @Joel 是的,我明白为什么酸洗对我没有帮助。并且节点的数据类型也是整数

标签: python graph networkx large-data


【解决方案1】:

您的 RAM 比解决此问题所需的要小。 2**33*5000*2 = 85,899,345,920,000 取决于有多少节点/边缘,我不确定这是否适合您。但有希望。这取决于重复的元素,如果有很多那么......很好。如果不是这样,仅在您的机器上可能无法实现(开始将 AWS 视为运行此问题的平台)。

当您处理大型数据集时,您将谈论创建生成器而不是函数。 (开始使用那个 yield 关键字)。这个过滤过程应该在加载所有数据之前首先出现。由于您的问题的内存有限,因此您将编写文件。

在第一次通过时,我会使用生成器生成元组对,该生成器会跟踪它发送了哪些(下面的示例)。由于您使用的是有向图而不是多向图,因此您可以将所有边作为元组并将它们添加到生成器中的 set() 中。这将只产生独特的边缘。如果有一种方法可以遍历从 Node1 开始的所有边开始的节点,那么您可以进一步细分问题,将所有节点置于 for 循环中并在每个新节点处擦除 set()。 (我不知道那个函数(不同的初始条件)能做什么)

from pathlib import Path
def filter_edges():
    unique_edges = set()
    #Do some computations
    for i in range(2**33):
        #Do some computations
        edges = func(different initial conditions)
        for edge in edges:
            if edge not in unique_edges:
                 yield edge
                 unique_edges.add(edge)

def write_unique_values():
    for edge in filter_edges(): # it's easier on the machine to batch 10,000 or so rather than every line
        Path('edgelist.txt').write_text(edge)

def load_edgelist_to_graph():
    edges = Path('edgelist.txt').read_text().split('\n')
    G = nx.DiGraph()
    G.parse_edges(edges, ...)
    return G

write_unique_values()
G = load_edgelist_to_graph()

将生成器生成的边保存到文件中。或者甚至更好地分批 10000 左右(我将把它留给家庭作业)。

然后您将拥有一个具有独特边的文件,您可以将其加载到图表中。

你可以使用parse_edges解析边缘

【讨论】:

  • 感谢您的回答,但这并不能完全回答我的问题。原因是 'func' 每次运行时都会给出非常随机的边列表。而且由于我需要找到图形的吸引分量,我需要将所有加载到我的内存中的边都加载到图形中,然后计算吸引的 ccomponents。所以我的问题是如何将图形保存在我的磁盘而不是内存上,然后计算吸引组件。
  • 那么听起来您正在尝试制作一个鄂尔多斯-renyi 图networkx.github.io/documentation/networkx-1.10/reference/… 并找到类似中心性的东西,并且没有称为“吸引组件”的术语,但有中心性分数。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-06
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
相关资源
最近更新 更多