【问题标题】:Python Networkx: preserving nodes ID when saving/serializing networks to hardiskPython Networkx:将网络保存/序列化到硬盘时保留节点ID
【发布时间】:2016-08-10 18:22:37
【问题描述】:

我在 Python 中使用 networkx1.10 进行一个项目,该项目需要将网络转储到硬盘上,然后重新加载它们,以便继续执行一些操纵此类网络的算法。

我一直在尝试用几种不同的方式来做到这一点:首先使用 nx.write_gml() 和 nx_read_gml(),现在使用 pickle/cpickle。

虽然从表面上看一切正常,但我注意到无论保存/加载是否在某个时间点发生,我在模拟中都会得到不同的结果。

我认为这可能与某些网络似乎被转储/重新加载过程修改的事实有关(这当然是出乎意料的)。

为了调试,现在我正在使用 pickle 保存和重新加载每个网络,比较转储/重新加载前后它们的 gml 表示(通过 nx.write_gml / nx.generate_gml 实现)。这样做,我注意到了一些差异。

在某些情况下,只是某些图形属性的顺序被修改,不会对我的程序造成任何伤害。在其他情况下,两条边在 gml 表示中出现的顺序是不同的,同样没有害处。

但是,通常会修改某些节点的 ID,如下例所示:

https://www.diffchecker.com/zvzxrshy

虽然边缘似乎进行了相应的修改,因此网络看起来是等效的,但 ID 的这种变化可能会改变我的模拟(原因我不打算解释)。

我相信这可能是我问题的根源。

您知道为什么会发生这种情况吗,即使使用低级序列化机制(例如由 pickle/cpickle 实现的那些机制)?

如何确保序列化过程前后的网络完全相同?

我正在做这样的事情:

with open('my_network.pickle', 'wb') as handle:
    pickle.dump(my_network, handle, protocol=pickle.HIGHEST_PROTOCOL)
...
with open('my_network.pickle', 'rb') as handle:
    my_network_reloaded = pickle.load(handle)

# compare nx.write_gml for my_network and my_network_reloaded

任何帮助将不胜感激:过去三天我一直在与这个问题作斗争,我快疯了!

谢谢

【问题讨论】:

  • 我无法从文档中真正看出,但使用 Python 的 pickle 和 write_gpickle 和 read_gpickle (description) 有什么区别吗?
  • 我在使用这两种方法时遇到了问题...
  • 你的问题的症结是“(原因我不打算解释)”。如果您确实需要生成具有特定 id 和排序的 gml 格式输出,则需要修改现有编写器或编写一些自定义软件来执行此操作。您可以使用 id 以外的其他属性来标记您的节点吗? (对于 gml 格式,那些需要是整数并自动生成以确保)。
  • @Aric 我认为在序列化网络时节点 ID 的这些变化可能是我问题的根源,因为我的算法确实以可能对这些变化敏感的方式操纵网络。有时我会像这样随机选择节点(和边):random.choice(G.nodes()),并在该节点/边上执行一些操作(例如修改属性、删除节点、添加边等.)。我担心如果节点的 ordering/id 发生变化,我最终可能会选择不同的节点而不是我会选择的节点,因此,我会改变整体结果。

标签: python serialization pickle networkx gml


【解决方案1】:

它们似乎是相同的图,直到同构。

您的问题可能是节点顺序。实际上,networkx 使用 dicts 来存储节点和边,它们是无序和随机的。

您有两种解决方案:要么忽略它,要么使用有序图:

>>> class OrderedGraph(nx.Graph):
...    node_dict_factory = OrderedDict
...    adjlist_dict_factory = OrderedDict
>>> G = OrderedGraph()
>>> G.add_nodes_from( (2,1) )
>>> G.nodes()
[2, 1]
>>> G.add_edges_from( ((2,2), (2,1), (1,1)) )
>>> G.edges()
[(2, 2), (2, 1), (1, 1)]

(来自the documentation of the Graph class的示例)

【讨论】:

  • 我开始认为您可能是对的,我会对此进行测试。不过,我不明白为什么在泡菜调用之间会发生这样的事情。我可能期望额外的 networkx 操作来改变顺序,但不是 pickle。也许它在内存中以不同的方式恢复对象,并且 networkx 以某种方式相应地重组了图形?您是否认为手动对未排序的图进行排序(使用topological_sort 也可以?
  • Pickling 存储内容,而不是数据结构的确切内存布局,这是故意随机化的。而topological_sort 不会对图进行排序(无论如何,它的数据结构本质上是无序的),而是在不更改图的情况下返回节点列表。
  • 感谢您的建议。好吧,明天我将首先尝试明确分配 ID,希望读/写功能不会与这些功能混淆(我已经读过它们只有在未指定时才在内部进行管理)。如果这不起作用,我将尝试您的解决方案。我会及时通知你们。
  • 如果你想要一些特殊的命令,你将需要修改 gml.py 中的编写器。 id 是在运行时根据 list(G) 中的顺序生成的。
  • @ValentinLorentz 我尝试了您的 OrderedGraph 解决方案,但在这一行出现错误:nx.simple_cycles(G) File "mytest.py", line 2685, in hasCycles return sum(1 for e in nx.simple_cycles(G)) != 0 文件“”,第 2 行,simple_cycles 文件“/usr/local/lib/python2.7/dist-packages/networkx/utils/decorators.py ",第 66 行,在 _not_implemented_for ' '.join(graph_types)) 看起来我的图表不再有方向。事实上,我们怎么说我们仍然想要一个有向图呢?我尝试在 OrderedGraph(nx.DiGraph) 类中更改 OrderedGraph(nx.Graph),但没有结果
猜你喜欢
  • 2021-04-27
  • 2015-05-16
  • 1970-01-01
  • 1970-01-01
  • 2021-03-13
  • 1970-01-01
  • 2013-11-02
  • 1970-01-01
  • 2011-08-20
相关资源
最近更新 更多