本文最后更新于:2025年9月1日 下午

NetworkX 是一个功能强大的 Python 库,用于创建、操作和研究复杂网络(或图)的结构、动力学和功能。本文记录相关内容。

简介

无论是社交网络分析、基础设施规划、生物信息学还是机器学习中的图结构数据,NetworkX 都能提供丰富的工具和算法。下面我将为你介绍 NetworkX 的主要功能和使用方法。

NetworkX 的设计目标是灵活性和易用性,其主要特点包括:

  • 支持多种图类型:包括无向图 (Graph)、有向图 (DiGraph)、多重无向图 (MultiGraph) 和多重有向图 (MultiDiGraph)136。
  • 灵活的节点和边:节点和边可以是任何可哈希的 Python 对象(如数字、字符串、其他图对象),并且可以附带任意属性的字典1710。
  • 丰富的图论算法:内置了大量经典的图论算法,用于最短路径、中心性计算、社区检测、连通性分析等。
  • 可视化工具:虽然主要用于分析,但也提供了基本的绘图功能,可与 Matplotlib 和 Graphviz 集成进行可视化136。
  • 易于集成:可以方便地与 SciPy、Pandas 等科学计算库配合使用,支持多种格式的图数据读写。

官方网站:https://networkx.org/

安装

安装 NetworkX 非常简单,使用 pip 命令即可:

1
pip install networkx

当前(2025.08.27)最新版本 3.5

图、边基本使用

下面我们通过一些基本操作来了解如何使用 NetworkX。

创建图

根据定义, Graph 是节点(顶点)以及已识别的节点对(称为边、链接等)的集合。在 NetworkX 中,节点可以是任何可哈希对象,例如文本字符串、图像、XML 对象、另一个 Graph、自定义节点对象等。

首先需要导入库并创建一个空的图对象:

1
2
3
4
5
6
7
import networkx as nx

# 创建不同类型的图
G = nx.Graph() # 无向图
DG = nx.DiGraph() # 有向图
MG = nx.MultiGraph() # 多重无向图
MDG = nx.MultiDiGraph() # 多重有向图

添加节点(Nodes)

节点是图的基本元素,可以单独添加,也可以从列表或其他图中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
G = nx.Graph()

# 添加单个节点
G.add_node(1)
G.add_node("Node_A")

# 从列表添加多个节点
G.add_nodes_from([2, 3, 4])

# 添加带属性的节点
G.add_nodes_from([
(5, {"color": "red", "size": 10}),
(6, {"color": "blue", "size": 15})
])

G.add_node(index, pos=[10, 10])

注意:节点可以是数字、字符串、元组等任何可哈希的 Python 对象。

一个图中的节点可以合并到另一个图中:

1
2
H = nx.path_graph(10)
G.add_nodes_from(H)

查看节点

如果你知道节点的 ID(即你在代码中使用的 index),可以直接访问该节点的所有属性:

1
2
3
4
5
6
7
8
9
10
11
# 假设节点的 ID 是 5
node_id = 5
node_attributes = G.nodes[node_id]
print(f"节点 {node_id} 的所有属性: {node_attributes}")

# 或者直接访问节点的 'pos' 属性(坐标信息)
node_pos = G.nodes[node_id]['pos']
print(f"节点 {node_id} 的坐标: {node_pos}")

# 获取所有节点的 ID 列表
all_node_ids = list(G.nodes())

添加边(Edges)

边连接节点,表示节点之间的关系或交互:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 添加单条边
G.add_edge(1, 2)
e = (2, 3)
G.add_edge(*e) # unpack edge tuple*

# 添加多条边
G.add_edges_from([(1, 3), (2, 4), (2, 5)])

# 添加带属性的边(例如权重)
G.add_edge(3, 4, weight=2.5, relation='connected')
G.add_edges_from([(4, 5, {'weight': 0.5, 'relation': 'weak'}),
(5, 6, {'weight': 1.2, 'relation': 'strong'})])

# 添加其他节点的边
G.add_edges_from(H.edges)

# 删除所有节点和边后
G.clear()

注意:如果添加边时涉及的节点尚不存在,NetworkX 会自动将这些节点添加到图中。

删除元素

可以像添加类似的方式从图形中删除节点和边。使用方法 Graph.remove_node()Graph.remove_nodes_from()Graph.remove_edge() Graph.remove_edges_from() ,例如:

1
2
3
4
5
6
G.remove_node(2)
G.remove_nodes_from("spam")
list(G.nodes)

G.remove_edge(1, 3)
list(G)

使用图形构造函数

图形对象不必增量构建 - 指定图形结构的数据可以直接传递给各种图形类的构造函数。通过实例化其中一个图形类来创建图形结构时,可以指定多种格式的数据。

1
2
3
4
5
6
G.add_edge(1, 2)
H = nx.DiGraph(G) # create a DiGraph using the connections from G
list(H.edges())

-->
[(1, 2), (2, 1)]
1
2
3
4
5
6
edgelist = [(0, 1), (1, 2), (2, 3)]
H = nx.Graph(edgelist) # create a graph from an edge list
list(H.edges())

-->
[(0, 1), (1, 2), (2, 3)]
1
2
3
4
5
6
adjacency_dict = {0: (1, 2), 1: (0, 2), 2: (0, 1)}
H = nx.Graph(adjacency_dict) # create a Graph dict mapping nodes to nbrs
list(H.edges())

-->
[(0, 1), (0, 2), (1, 2)]

用作节点和边的内容

您可能会注意到,节点和 Edge 未指定为 NetworkX 对象。这使您可以自由地使用有意义的项目作为节点和边。最常见的选择是数字或字符串,但节点可以是任何可哈希对象(除了 None ),并且可以使用 G.add_edge(n1, n2, object=x) 将边与任何对象 x 相关联。

访问边缘和邻居

除了视图 Graph.edgesGraph.adj 之外,还可以使用下标表示法访问边和邻居。

1
2
3
4
5
6
7
8
9
10
11
12
G = nx.Graph([(1, 2, {"color": "yellow"})])
G[1] # same as G.adj[1]
-->
AtlasView({2: {'color': 'yellow'}})

G[1][2]
-->
{'color': 'yellow'}

G.edges[1, 2]
-->
{'color': 'yellow'}

如果边已经存在,则可以使用下标表示法获取/设置边的属性。

1
2
3
4
5
6
7
G.add_edge(1, 3)
G[1][3]['color'] = "blue"
G.edges[1, 2]['color'] = "red"
G.edges[1, 2]

-->
{'color': 'red'}

使用 、 或 G.adj.items() 实现 G.adjacency() 所有(节点、邻接)对的快速检查。请注意,对于无向图,邻接迭代会看到每条边两次。

1
2
3
4
5
6
7
8
9
10
11
12
FG = nx.Graph()
FG.add_weighted_edges_from([(1, 2, 0.125), (1, 3, 0.75), (2, 4, 1.2), (3, 4, 0.375)])
for n, nbrs in FG.adj.items():
for nbr, eattr in nbrs.items():
wt = eattr['weight']
if wt < 0.5: print(f"({n}, {nbr}, {wt:.3})")

-->
(1, 2, 0.125)
(2, 1, 0.125)
(3, 4, 0.375)
(4, 3, 0.375)

使用 edges 属性可以方便地访问所有边缘。

1
2
3
4
5
6
7
for (u, v, wt) in FG.edges.data('weight'):
if wt < 0.5:
print(f"({u}, {v}, {wt:.3})")

-->
(1, 2, 0.125)
(3, 4, 0.375)

查看图的基本信息

创建图后,可以轻松查看其基本信息:

1
2
3
4
5
6
print("节点列表:", list(G.nodes()))
print("边列表:", list(G.edges()))
print("节点数量:", G.number_of_nodes())
print("边数量:", G.number_of_edges())
print("节点1的邻居:", list(G.neighbors(1))) # 获取某个节点的所有邻居节点
print("节点1的度:", G.degree[1]) # 获取某个节点的度(连接的边数)

可视化图

虽然 NetworkX 的主要焦点是分析,但它提供了使用 Matplotlib 的基本绘图功能:

1
2
3
4
5
import matplotlib.pyplot as plt

# 简单绘制图形
nx.draw(G, with_labels=True, node_color='lightblue', node_size=500, font_size=10)
plt.show()

你可以使用不同的布局来改变节点的位置,使图形更清晰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import networkx as nx
import matplotlib.pyplot as plt


G = nx.Graph()

# 添加单个节点
G.add_node(1)
G.add_node("Node_A")

# 从列表添加多个节点
G.add_nodes_from([2, 3, 4])

# 添加带属性的节点
G.add_nodes_from([
(5, {"color": "red", "size": 10}),
(6, {"color": "blue", "size": 15})
])

# 添加单条边
G.add_edge(1, 2)
e = (2, 3)
G.add_edge(*e) # unpack edge tuple*

# 添加多条边
G.add_edges_from([(1, 3), (2, 4), (2, 5)])

# 添加带属性的边(例如权重)
G.add_edge(3, 4, weight=2.5, relation='connected')
G.add_edges_from([(4, 5, {'weight': 0.5, 'relation': 'weak'}),
(5, 6, {'weight': 1.2, 'relation': 'strong'})])

# 使用不同布局
# pos = nx.spring_layout(G) # Fruchterman-Reingold 力导向布局
pos = nx.circular_layout(G) # 环形布局
# pos = nx.random_layout(G) # 随机布局
# pos = nx.shell_layout(G) # 同心圆壳布局

nx.draw(G, with_labels=True, node_color='lightblue', node_size=500, font_size=10)
plt.show()

子图

1
2
3
4
5
6
G = nx.petersen_graph()
subax1 = plt.subplot(121)
nx.draw(G, with_labels=True, font_weight='bold')
subax2 = plt.subplot(122)
nx.draw_shell(G, nlist=[range(5, 10), range(5)], with_labels=True, font_weight='bold')
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
options = {
'node_color': 'black',
'node_size': 100,
'width': 3,
}
subax1 = plt.subplot(221)
nx.draw_random(G, **options)
subax2 = plt.subplot(222)
nx.draw_circular(G, **options)
subax3 = plt.subplot(223)
nx.draw_spectral(G, **options)
subax4 = plt.subplot(224)
nx.draw_shell(G, nlist=[range(5,10), range(5)], **options)

要将绘图保存到文件,请使用:

1
2
nx.draw(G)
plt.savefig("path.png")

此函数写入本地目录中的文件 path.png 。如果您的系统上有 Graphviz 和 PyGraphviz 或 pydot,您还可以使用 networkx.drawing.nx_agraph.graphviz_layoutnetworkx.drawing.nx_pydot.graphviz_layout 来获取节点位置,或以点格式编写图形以供进一步处理。

1
2
3
4
from networkx.drawing.nx_pydot import write_dot
pos = nx.nx_agraph.graphviz_layout(G)
nx.draw(G, pos=pos)
write_dot(G, 'file.dot')

向图形、节点和边添加属性

图形属性

创建新图时分配图属性

1
2
3
4
5
G = nx.Graph(day="Friday")
G.graph

-->
{'day': 'Friday'}

可以稍后修改属性

1
2
3
4
5
G.graph['day'] = "Monday"
G.graph

-->
{'day': 'Monday'}

节点属性

使用 add_node() 、 或 add_nodes_from() G.nodes 添加节点属性

1
2
3
4
5
6
G.add_node(1, time='5pm')
G.add_nodes_from([3], time='2pm')
G.nodes[1]

-->
{'time': '5pm'}
1
2
3
4
5
G.nodes[1]['room'] = 714
G.nodes.data()

-->
NodeDataView({1: {'time': '5pm', 'room': 714}, 3: {'time': '2pm'}})

请注意,添加节点 G.nodes 不会将其添加到图形中,用于 G.add_node() 添加新节点。边缘也是如此。

边缘属性

使用 、 或 add_edges_from() 下标表示法添加 add_edge() /更改边属性。

1
2
3
4
5
G.add_edge(1, 2, weight=4.7 )
G.add_edges_from([(3, 4), (4, 5)], color='red')
G.add_edges_from([(1, 2, {'color': 'blue'}), (2, 3, {'weight': 8})])
G[1][2]['weight'] = 4.7
G.edges[3, 4]['weight'] = 4.2

特殊属性 weight 应该是数字,因为它被需要加权边的算法使用。

图生成与图操作

传统图操作

操作 含义
subgraph(G, nbunch) 返回在 nbunch 中的节点上诱导的子图。
union(G, H[, rename]) 合并图
disjoint_union(G, H) 合并图
cartesian_product(G, H) 返回 G 和 H 的笛卡尔积。
compose(G, H) 通过将节点和边组合成单个图,将图 G 与 H 组合成一个图。
complement(G) 返回 G 的图补图。
create_empty_copy(G[, with_data]) 返回删除所有边的图形 G 的副本。
to_undirected(graph) 返回图形的无向视图 graph
to_directed(graph) 返回图形的有向视图 graph

使用生成器生成经典图

complete_graph (n[, create_using]) 返回 K_n 具有 n 个节点的完整图。
complete_bipartite_graph (n1, n2[, create_using]) 返回完整的二分图 K_{n_1,n_2}
barbell_graph (m1,m2[,create_using]) 返回杠铃图:两个由路径连接的完整图。
lollipop_graph (m,n[,create_using]) 返回棒棒糖图; K_m 连接到 P_n

例如:

1
2
3
4
K_5 = nx.complete_graph(5)
K_3_5 = nx.complete_bipartite_graph(3, 5)
barbell = nx.barbell_graph(10, 10)
lollipop = nx.lollipop_graph(10, 20)

随机图生成器

erdos_renyi_graph (n, p[, seed, directed, …]) 返回一个 随机图,也称为 Erdős-Rényi 图或二项式图。
watts_strogatz_graph (n, k, p[, seed, …]) 返回 Watts-Strogatz 小世界图。
barabasi_albert_graph (n, m[, seed, …]) 使用 Barabási-Albert 优先附件返回随机图
random_lobster(n, p1, p2[, seed, create_using]) 返回随机龙虾图。

例如:

1
2
3
4
er = nx.erdos_renyi_graph(100, 0.15)
ws = nx.watts_strogatz_graph(30, 3, 0.1)
ba = nx.barabasi_albert_graph(100, 5)
red = nx.random_lobster(100, 0.9, 0.9)

图存储与读取

NetworkX 支持许多流行的格式,例如边缘列表、邻接列表、GML、GraphML、LEDA 等。

1
2
nx.write_gml(red, "path.to.file")
mygraph = nx.read_gml("path.to.file")

图的分析与算法

NetworkX 的真正强大之处在于其丰富的图论算法。以下是一些常见分析任务的示例:

度中心性(Degree Centrality)

衡量节点通过其边直接连接其他节点的能力:

1
2
degree_centrality = nx.degree_centrality(G)
print("度中心性:", degree_centrality)

最短路径(Shortest Path)

查找图中两个节点之间的最短路径:

1
2
3
4
5
6
7
# 计算节点1到节点4的最短路径
shortest_path = nx.shortest_path(G, source=1, target=4)
print("最短路径:", shortest_path)

# 计算所有节点对之间的最短路径长度
shortest_path_lengths = dict(nx.all_pairs_shortest_path_length(G))
print("所有节点对的最短路径长度:", shortest_path_lengths)

nx.shortest_path 默认使用 Dijkstra 算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import networkx as nx
import numpy as np
# networkX 自带 A* 算法
# 假设 G 是已经构建好的 networkx 图,节点有 pos 属性
# 定义启发式函数(欧几里得距离)
def euclidean_heuristic(u, v, G):
pos_u = G.nodes[u]['pos'] # 获取节点 u 的坐标
pos_v = G.nodes[v]['pos'] # 获取节点 v 的坐标
return np.linalg.norm(pos_u - pos_v)

# 计算从节点 1 到节点 4 的最短路径
try:
shortest_path = nx.astar_path(G, source=1, target=4, heuristic=lambda u, v: euclidean_heuristic(u, v, G), weight='weight')
path_length = nx.astar_path_length(G, source=1, target=4, heuristic=lambda u, v: euclidean_heuristic(u, v, G), weight='weight')
print(f"A* Shortest path: {shortest_path}")
print(f"A* Path length: {path_length}")
except nx.NetworkXNoPath:
print("No path exists between nodes 1 and 4.")

连通分量(Connected Components)

对于无向图,查找所有连通分量:

1
2
3
4
5
6
7
# 查找所有连通分量
connected_components = list(nx.connected_components(G))
print("连通分量:", connected_components)

# 检查图是否连通
is_connected = nx.is_connected(G)
print("图是否连通:", is_connected)

其他常用算法

NetworkX 还提供了许多其他算法,如聚类系数、PageRank、社区检测等

1
2
3
4
5
6
7
# 计算聚类系数
clustering_coefficient = nx.clustering(G)
print("聚类系数:", clustering_coefficient)

# 计算PageRank (常用于有向图)
pagerank = nx.pagerank(DG) # DG 是一个有向图
print("PageRank:", pagerank)

参考资料



文章链接:
https://www.zywvvd.com/notes/coding/python/python-networkx/python-networkx/


“觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭”

微信二维码

微信支付

支付宝二维码

支付宝支付

Python NetworkX 教程
https://www.zywvvd.com/notes/coding/python/python-networkx/python-networkx/
作者
Yiwei Zhang
发布于
2025年8月27日
许可协议