本文最后更新于: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 命令即可:
当前(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
| node_id = 5 node_attributes = G.nodes[node_id] print(f"节点 {node_id} 的所有属性: {node_attributes}")
node_pos = G.nodes[node_id]['pos'] print(f"节点 {node_id} 的坐标: {node_pos}")
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)
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) list(H.edges())
--> [(1, 2), (2, 1)]
|
1 2 3 4 5 6
| edgelist = [(0, 1), (1, 2), (2, 3)] H = nx.Graph(edgelist) 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) list(H.edges())
--> [(0, 1), (0, 2), (1, 2)]
|
用作节点和边的内容
您可能会注意到,节点和 Edge 未指定为 NetworkX 对象。这使您可以自由地使用有意义的项目作为节点和边。最常见的选择是数字或字符串,但节点可以是任何可哈希对象(除了 None
),并且可以使用 G.add_edge(n1, n2, object=x)
将边与任何对象 x
相关联。
访问边缘和邻居
除了视图 Graph.edges
和 Graph.adj
之外,还可以使用下标表示法访问边和邻居。
1 2 3 4 5 6 7 8 9 10 11 12
| G = nx.Graph([(1, 2, {"color": "yellow"})]) G[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)
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.circular_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_layout
或 networkx.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
应该是数字,因为它被需要加权边的算法使用。
图生成与图操作
传统图操作
使用生成器生成经典图
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
| 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
def euclidean_heuristic(u, v, G): pos_u = G.nodes[u]['pos'] pos_v = G.nodes[v]['pos'] return np.linalg.norm(pos_u - pos_v)
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 = nx.pagerank(DG) print("PageRank:", pagerank)
|
参考资料
文章链接:
https://www.zywvvd.com/notes/coding/python/python-networkx/python-networkx/