从2.X迁移到3.0的迁移指南#

Note

在NetworkX 3.0发布之前的工作将包含在NetworkX 2.6、2.7和2.8的发布中。例如,我们在这些版本中正在弃用许多旧代码。本指南将讨论这一持续的工作,并帮助您了解现在可以做出哪些更改,以最小化由迁移到3.0引起的中断。

这是一份供从NetworkX 2.X迁移到NetworkX 3.0的人使用的指南。

这些问题可以在 邮件列表 上讨论。

3.0版本的重点是解决多年的技术债务,现代化我们的代码库,提高性能,并使贡献变得更加容易。 我们计划在夏季发布3.0版本。

默认依赖项#

我们不再依赖于”decorator”库,因此NetworkX不再有任何依赖项。 然而,NetworkX 3.0包括许多围绕与其他科学Python库(如 numpyscipymatplotlibpandas )更紧密集成的变化和改进。

对于NetworkX的核心功能(如数据结构( GraphDiGraph 等)和常见算法),没有任何依赖项,但是一些功能,例如 networkx.linalg 包中的函数,仅在安装了这些额外的库时才可用。

与科学Python更好地集成#

NetworkX 3.0包括几项改进和现代化 numpyscipy 在networkx中的使用的变化。

用数组替换NumPy/SciPy矩阵#

长期以来, numpy.matrix 一直不被推荐使用,因为它与 ndarray 接口有显著差异,主要包括:

  • 矩阵始终是二维的,导致在常见操作(如索引和广播)中产生不同的结果。

  • 乘法运算符被解释为矩阵乘法,而不是逐元素乘法。

这些差异使得代码更难理解,并且通常需要样板代码才能处理多种格式。 随着scipy版本1.8中稀疏数组接口的添加,NetworkX 3.0已经用它们的数组对应物替换了所有scipy稀疏矩阵和numpy矩阵的实例。 在NetworkX 3.X中,任何返回 scipy.sparse.spmatrixnumpy.matrix 对象的函数现在将返回它们对应的数组版本(分别为 scipy.sparse._sparraynumpy.ndarray ),并且已删除导致矩阵对象的显式转换函数(例如 to_numpy_matrix )。用户应该期望所有 numpyscipy.sparse 对象在NetworkX 3.X中遵循*array*语义。

切换到NumPy/SciPy实现作为某些算法的默认实现#

一些NetworkX分析算法可以使用线性代数实现非常高的性能,例如 pagerank 算法。在NetworkX 2.0中, pagerank 算法有多个实现版本: pagerank (纯Python实现)、 pagerank_numpy (用于稠密邻接矩阵)和 pagerank_scipy (稀疏邻接矩阵)。在所有实际用例中,SciPy实现远远优于其他实现。在NetworkX 3.0中, pagerank 函数现在默认使用SciPy实现。这意味着调用 nx.pagerank 现在需要安装SciPy。原始的Python实现仍可用于教学目的,命名为 networkx.algorithms.link_analysis.pagerank_alg._pagerank_python ,但不会公开暴露以阻止其使用。

支持 numpy.random.Generator#

NumPy v1.17引入了伪随机数生成的新接口。 py_random_statenp_random_state 装饰器已添加对新的 numpy.random.Generator 实例的支持;换句话说, seed 参数现在接受 numpy.random.Generator 实例:

   >>> G = nx.barbell_graph(6, 2)
   >>> pos = nx.spring_layout(G, seed=np.random.default_rng(123456789))

`numpy.random.Generator` 接口相比原始的 `numpy.random.RandomState` 包括几项改进,包括更好的统计特性和改进的性能。然而, ``Generator`` 与 ``RandomState`` 不兼容流式操作,并且不能保证与未来版本的NumPy兼容。因此,在使用随机数生成器时最佳实践是要明确。为了确保在NetworkX的所有版本(过去和未来)中**精确**可重现随机数,建议使用 ``RandomState`` ::

   >>> rng = np.random.RandomState(12345)
   >>> pos = nx.spring_layout(G, seed=rng)

对于不太重要的确切流复现性的新代码,建议使用 Generator

>>> rng = np.random.default_rng(12345)
>>> pos = nx.spring_layout(G, seed=rng)

Note

使用 Generator 实现确切的随机数复现仍然可能,但可能需要安装特定版本的numpy。

多属性邻接矩阵的NumPy结构化数据类型#

在NetworkX 3.0之前,通过 nx.to_numpy_recarray 转换函数支持多属性邻接矩阵。

numpy.recarray 是围绕 ndarray 的便利包装器,具有结构化数据类型。

因此,在NetworkX 3.0中,已删除此转换函数,并改为在 to_numpy_array 中添加对结构化数据类型的支持,通常改善了多属性邻接数组表示的支持:

>>> import numpy as np
>>> edges = [
...     (0, 1, {"weight": 10, "cost": 2}),
...     (1, 2, {"weight": 5, "cost": 100})
... ]
>>> G = nx.Graph(edges)
>>> # 创建具有"weight"和"cost"属性的邻接矩阵
>>> dtype = np.dtype([("weight", float), ("cost", int)])
>>> A = nx.to_numpy_array(G, dtype=dtype, weight=None)
>>> A
array([[( 0.,   0), (10.,   2), ( 0.,   0)],
       [(10.,   2), ( 0.,   0), ( 5., 100)],
       [( 0.,   0), ( 5., 100), ( 0.,   0)]],
      dtype=[('weight', '<f8'), ('cost', '<i8')])
>>> A["cost"]
array([[  0,   2,   0],
       [  2,   0, 100],
       [  0, 100,   0]])
>>> # 可以使用 ``view`` 恢复recarray接口
>>> A = nx.to_numpy_array(G, dtype=dtype, weight=None).view(np.recarray)
>>> A
rec.array([[( 0.,   0), (10.,   2), ( 0.,   0)],
           [(10.,   2), ( 0.,   0), ( 5., 100)],
           [( 0.,   0), ( 5., 100), ( 0.,   0)]],
          dtype=[('weight', '<f8'), ('cost', '<i8')])
>>> A.weight
array([[ 0., 10.,  0.],
       [10.,  0.,  5.],
       [ 0.,  5.,  0.]])

已弃用的代码#

函数 read_gpicklewrite_gpickle 在3.0中已移除。 您可以将NetworkX图读取和写入为Python pickle。

>>> import pickle
>>> G = nx.path_graph(4)
>>> with open('test.gpickle', 'wb') as f:
...     pickle.dump(G, f, pickle.HIGHEST_PROTOCOL)
...
>>> with open('test.gpickle', 'rb') as f:
...     G = pickle.load(f)
...

函数 read_yamlwrite_yaml 在3.0中已移除。 您可以使用pyyaml以YAML格式读取和写入NetworkX图。

>>> import yaml
>>> G = nx.path_graph(4)
>>> with open('test.yaml', 'w') as f:
...     yaml.dump(G, f)
...
>>> with open('test.yaml', 'r') as f:
...     G = yaml.load(f, Loader=yaml.Loader)