从 2.X 到 3.0 的迁移指南#
注意
导致 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 库更紧密集成而进行的更改和改进;特别是 numpy
、scipy
、matplotlib
和 pandas
。
NetworkX 的核心功能,例如数据结构(Graph
、DiGraph
等)和常用算法,没有强制依赖项,但某些功能(例如 networkx.linalg
包中的函数)只有在安装了这些额外库时才可用。
改进与科学计算 Python 的集成#
NetworkX 3.0 包含多项更改,以改进和现代化 networkx 中 numpy
和 scipy
的使用方式。
-
移除所有
numpy.matrix
的使用,转而使用numpy.ndarray
。采用 scipy.sparse 的 数组 接口。
支持使用
numpy.random.Generator
生成随机数。用对结构化 dtypes 更通用的支持替代 recarray 支持。
用数组替代 NumPy/SciPy 矩阵#
numpy.matrix
由于与 ndarray
接口存在显著差异,长期以来一直不被推荐使用,主要差异在于
矩阵始终是二维的,导致索引和广播等常见操作的结果不同。
乘法运算符被解释为矩阵乘法,而不是元素级乘法。
这些差异使得代码更难理解,并且通常需要样板代码来处理多种格式。随着 scipy 1.8 版本中增加了稀疏数组接口,NetworkX 3.0 已将所有 scipy 稀疏矩阵和 numpy 矩阵实例替换为其相应的数组对应项。任何返回 scipy.sparse.spmatrix
或 numpy.matrix
对象的函数现在都返回其对应的数组对应项(分别为 scipy.sparse._sparray
和 numpy.ndarray
),并且已移除产生矩阵对象的显式转换函数(例如 to_numpy_matrix
)。用户应预期 NetworkX 3.X 中所有 numpy
和 scipy.sparse
对象都遵循 数组 语义。
某些算法默认切换到 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_state
和 np_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)
注意
使用 Generator
仍然可以实现随机数的精确重现,但这可能需要安装特定版本的 numpy。
多属性邻接矩阵的 NumPy 结构化 dtypes#
在 NetworkX 3.0 之前,通过 nx.to_numpy_recarray
转换函数支持多属性邻接矩阵。numpy.recarray
是 ndarray 的一个方便的包装器,支持结构化 dtypes。因此,此转换函数已在 NetworkX 3.0 中移除,而对结构化 dtypes 的支持已添加到
to_numpy_array
中,从而普遍提高了对多属性邻接数组表示的支持。
>>> import numpy as np
>>> edges = [
... (0, 1, {"weight": 10, "cost": 2}),
... (1, 2, {"weight": 5, "cost": 100})
... ]
>>> G = nx.Graph(edges)
>>> # Create an adjacency matrix with "weight" and "cost" attributes
>>> 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]])
>>> # The recarray interface can be recovered with ``view``
>>> 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_gpickle
和 write_gpickle
在 3.0 中已移除。您可以使用 Python pickle 格式读取和写入 NetworkX 图。
>>> 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_yaml
和 write_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)