数学建模社区-数学中国

标题: Python小白的数学建模课-图论的基本概念 [打印本页]

作者: 1047521767    时间: 2021-10-30 21:36
标题: Python小白的数学建模课-图论的基本概念
Python小白的数学建模课-图论的基本概念% G8 j# a. U' a, A7 Z

3 z+ [4 S. k  v% O8 q: w3 G+ G7 o, w9 P1 A: Q
1. 图论1.1 图论是什么9 P% C% `; ^- Y, n
图论〔Graph Theory〕以图为研究对象,是离散数学的重要内容。图论不仅与拓扑学、计算机数据结构和算法密切相关,而且正在成为机器学习的关键技术。
3 u: X1 A* b1 ?8 l/ [7 f: D: o4 L# U, ~9 R/ U, V' T# |& v; k6 ?
图论中所说的图,不是指图形图像(image)或地图(map),而是指由顶点(vertex)和连接顶点的边(edge)所构成的关系结构。, i1 C% D, ^) e$ L4 Q2 a8 a

" h+ O  m, ^* A. V; f9 j2 b& |图提供了一种处理关系和交互等抽象概念的更好的方法,它还提供了直观的视觉方式来思考这些概念。) G' E- D2 w1 v/ J" |# w: [

% u- {. Y# H1 m  ^, x4 d1.2 NetworkX 工具包2 ~3 t; d# p* ]0 e
NetworkX 是基于 Python 语言的图论与复杂网络工具包,用于创建、操作和研究复杂网络的结构、动力学和功能。# }. \' `& t; z* M4 z. Z8 U

& m) s6 L- L7 R$ u9 Y/ `NetworkX 可以以标准和非标准的数据格式描述图与网络,生成图与网络,分析网络结构,构建网络模型,设计网络算法,绘制网络图形。7 t  e' A; u* Q1 ^- e& T

+ A' L: @4 B/ x" x1 b% K; tNetworkX 提供了图形的类、对象、图形生成器、网络生成器、绘图工具,内置了常用的图论和网络分析算法,可以进行图和网络的建模、分析和仿真。4 Y' M/ o8 N- x) e) ]" N- \

; s: U% J, e! Z5 l5 ANetworkX 的功能非常强大和庞杂,所涉及内容远远、远远地超出了数学建模的范围,甚至于很难进行系统的概括。本系列结合数学建模的应用需求,来介绍 NetworkX 图论与复杂网络工具包的基本功能和典型算法。
) O$ \  S" ^' K& j: I. W$ W% |6 z5 Q/ J
, z7 q* o6 T& e! J6 a+ M2 N: C
2、图、顶点和边的创建与基本操作
, ?1 h1 ]& }! A# q( r+ Y4 @

图由顶点和连接顶点的边构成,但与顶点的位置、边的曲直长短无关。

Networkx 支持创建简单无向图、有向图和多重图;内置许多标准的图论算法,节点可为任意数据;支持任意的边值维度,功能丰富,简单易用。

2.1 图的基本概念6 ]6 f9 o4 B! Y$ b  p" U# a. M- g
图(Graph):图是由若干顶点和连接顶点的边所构成关系结构。
% S& l4 F! r) ]2 h( a% j; u/ P. }顶点(Node):图中的点称为顶点,也称节点。
3 W+ D% x/ R' W! ~边(Edge):顶点之间的连线,称为边。+ z" l3 E1 J4 j  f+ ?* w% K) w
平行边(Parallel edge):起点相同、终点也相同的两条边称为平行边。
( e7 @5 n: l+ n' F& ~! Y( H, U循环(Cycle):起点和终点重合的边称为循环。
- y( f% O7 Y, `5 E& x有向图(Digraph):图中的每条边都带有方向,称为有向图。/ i) H" T* u. X; P6 e" ~
无向图(Undirected graph):图中的每条边都没有方向,称为无向图。. |5 v5 ?+ A+ L) @  L1 c
赋权图(Weighted graph):图中的每条边都有一个或多个对应的参数,称为赋权图。该参数称为这条边的权,权可以用来表示两点间的距离、时间、费用。
+ ~' [" E  f( i' B/ \度(Degree):与顶点相连的边的数量,称为该顶点的度。) u* O7 J5 T$ T8 y# H( E$ p, I' A7 {

( A6 n9 Q! w9 k3 ?! C2.2 图、顶点和边的操作9 n. _; s$ a: C
Networkx很容易创建图、向图中添加顶点和边、从图中删除顶点和边,也可以查看、删除顶点和边的属性。1 b, w. z+ Z' o, ]  @  J7 e- G

3 m- B, @' F) T" a# ]# K2.2.1 图的创建Graph() 类、DiGraph() 类、MultiGraph() 类和 MultiDiGraph() 类分别用来创建:无向图、有向图、多图和有向多图。定义和例程如下:
4 Y* Q# w* j+ N) B, Q8 e' X, N2 Y7 D" T) Z* m9 W0 N
class Graph(incoming_graph_data=None, **attr)6 |) {  V* [( o' R8 ]
import networkx as nx  # 导入 NetworkX 工具包% H# ~% O4 `( }
8 Z- O7 n% R+ u1 G3 T6 T* `# g" s
# 创建 图8 _$ T; ]. P9 U6 i% j1 x2 b1 J
G1 = nx.Graph()  # 创建:空的 无向图
+ V& f) N% ^; rG2 = nx.DiGraph()  #创建:空的 有向图
6 i% C: x6 ]" c9 v, VG3 = nx.MultiGraph()  #创建:空的 多图
% N' L4 h  H- I$ m! S( JG4 = nx.MultiDiGraph()  #创建:空的 有向多图# \+ G  G4 u8 l, b6 c4 X

: P# c6 `; F/ M# E( g
( [: h6 k+ k' n2.2.2 顶点的添加、删除和查看3 J  i3 _1 W; p; B' a4 N/ A

图的每个顶点都有唯一的标签属性(label),可以用整数或字符类型表示,顶点还可以自定义任意属性。

顶点的常用操作:添加顶点,删除顶点,定义顶点属性,查看顶点和顶点属性。定义和例程如下:


0 e6 u. @8 n. r: J, Q& v+ pGraph.add_node(node_for_adding, **attr): b# R9 u' y. o
Graph.add_nodes_from(nodes_for_adding, **attr)
) q; ^) ~9 m% y# E) M. Q) ?+ gGraph.remove_node(n)1 L. N% ?" o6 x& e/ o  E
Graph.remove_nodes_from(nodes)5 A. a4 P+ d$ }( U, |+ p" g

; g  C  m- v% c% {5 V! I# 顶点(node)的操作
+ Q. [6 |# ]0 P2 f( U! Y; M# 向图中添加顶点
! t7 H8 c* I* P$ B; I9 g' oG1.add_node(1)  # 向 G1 添加顶点 1
$ V4 [9 ]. g% Z. P  g! x4 UG1.add_node(1, name='n1', weight=1.0)  # 添加顶点 1,定义 name, weight 属性
$ T  O9 S3 c  |! G8 \# g% PG1.add_node(2, date='May-16') # 添加顶点 2,定义 time 属性5 Y6 R; ^0 P8 F( ^% D. e
G1.add_nodes_from([3, 0, 6], dist=1)  # 添加多个顶点,并定义属性
% p: ]" V" W; L5 S4 ?G1.add_nodes_from(range(10, 15))  # 向图 G1 添加顶点 10~14
/ C  D; ]& t5 d+ e# z1 f( w1 u
1 a/ s: a5 F5 K) [# 查看顶点和顶点属性
' l0 b' T; E  d/ s; e7 Iprint(G1.nodes())  # 查看顶点列表
! V* ]0 x6 |( S# [1, 2, 3, 0, 6, 10, 11, 12, 13, 14]6 z# _9 s% k/ _  g
print(G1._node)  # 查看顶点属性
4 D" r/ r' U" P% u" J; o7 Q" |1 M# {1: {'name': 'n1', 'weight': 1.0}, 2: {'date': 'May-16'}, 3: {'dist': 1}, 0: {'dist': 1}, 6: {'dist': 1}, 10: {}, 11: {}, 12: {}, 13: {}, 14: {}}8 O% _/ n# E% w% ^4 u0 P

) a6 o+ \6 N3 A0 a# 从图中删除顶点
0 o4 }2 k* y& d) c# q% PG1.remove_node(1)  # 删除顶点
4 Y9 g! T" [' `1 T( ]2 @& b( tG1.remove_nodes_from([1, 11, 13, 14])  # 通过顶点标签的 list 删除多个顶点$ a7 |( x: T+ Z+ F
print(G1.nodes())  # 查看顶点
# ~1 a, v. K$ E# [2, 3, 0, 6, 10, 12]  # 顶点列表) c/ f6 `& ?. r4 D4 H6 H* s0 F
2.2.3 边的添加、删除和查看

边是两个顶点之间的连接,在 NetworkX 中 边是由对应顶点的名字的元组组成 e=(node1,node2)。边可以设置权重、关系等属性。

边的常用操作:添加边,删除边,定义边的属性,查看边和边的属性。向图中添加边时,如果边的顶点是图中不存在的,则自动向图中添加该顶点。

Graph.add_edge(u_of_edge, v_of_edge, **attr)9 j; B. e% d" S  ^
Graph.add_edges_from(ebunch_to_add, **attr)- f0 b3 }4 X( s
Graph.add_weighted_edges_from(ebunch_to_add, weight=‘weight’, **attr)
0 j$ a9 \; P- Z5 g) F; a( p
% ^( f7 j, i" o# 边(edge)的操作. A  s9 U1 B, \
# 向图中添加边
: G0 H- O& {1 R# d$ |7 `G1.add_edge(1,5)  # 向 G1 添加边,并自动添加图中没有的顶点1 ^6 R! F' S6 F+ z0 }
G1.add_edge(0,10, weight=2.7)  # 向 G1 添加边,并设置边的属性
, Z  j8 }  R6 l' WG1.add_edges_from([(1,2,{'weight':0}), (2,3,{'color':'blue'})])  # 向图中添加边,并设置属性$ Z; d. l7 L, w  N' @& ^
G1.add_edges_from([(3,6),(1,2),(6,7),(5,10),(0,1)])  # 向图中添加多条边2 Y3 C2 J. T& Q/ b
G1.add_weighted_edges_from([(1,2,3.6),[6,12,0.5]])  # 向图中添加多条赋权边: (node1,node2,weight)0 V; w% ]- ~2 L5 G7 j
print(G1.nodes())  # 查看顶点
! t/ E& ^2 |9 ^5 L# [2, 3, 0, 6, 10, 12, 1, 5, 7]  # 自动添加了图中没有的顶点
/ T0 |" ~! [4 k! B& e7 R) `3 y: Z, Q9 N: G- n- r
# 从图中删除边
; j. B; H  G& ^- U* b3 J5 ?G1.remove_edge(0,1)  # 从图中删除边 0-14 ~2 ]* B4 v0 v' d* s
G1.remove_edges_from([(2,3),(1,5),(6,7)])  # 从图中删除多条边
3 \5 @! Z4 Q" w# _: o+ T: e7 \: G4 u: v5 j
# 查看 边和边的属性5 A( U5 b4 Q- |& s% w  n6 \. R
print(G1.edges)  # 查看所有的边+ i' |' g& ~7 L- `
[(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]7 I, F: J" L8 V
print(G1.get_edge_data(1,2))  # 查看指定边的属性
' A7 c1 }1 I$ s2 a" M' M: l3 [: s# {'weight': 3.6}3 @9 A+ Y+ q: v) b8 W- J
print(G1[1][2])  # 查看指定边的属性+ [; Y8 v: W) k: @5 d
# {'weight': 3.6}; |, C! x7 K9 p% E! ?  q
print(G1.edges(data=True))  # 查看所有边的属性
3 P, U* T4 ~. e2 y' X/ ~9 {. _& L# [(2, 1, {'weight': 3.6}), (3, 6, {}), (0, 10, {'weight': 2.7}), (6, 12, {'weight': 0.5}), (10, 5, {})]& W' I" [, g% q& U: U7 V+ r) d# z

% R3 l- b; z6 {, S7 S6 L7 J  `2.2.4 查看图、顶点和边的信息* V5 \! {8 l7 i# Q" S3 m: Y: s
% G! k/ e/ f3 o: k/ |
# 查看图、顶点和边的信息+ n% V, L1 d8 e! F6 M* A$ z
print(G1.nodes)  # 返回所有的顶点 [node1,...]
4 f& r) J5 S/ D9 f" @5 p6 O# [2, 3, 0, 6, 10, 12, 1, 5, 7]
# \3 k) K1 W8 g) B) wprint(G1.edges)  # 返回所有的边 [(node1,node2),...]9 ]  P- c. a# @4 e3 C' k; `- C
# [(2, 1), (3, 6), (0, 10), (6, 12), (10, 5)]/ L% Q, w2 r( `! F5 o6 z
print(G1.degree)  # 返回各顶点的度 [(node1,degree1),...]
8 b0 K6 {; j- k* p: t) y# [(2, 1), (3, 1), (0, 1), (6, 2), (10, 2), (12, 1), (1, 1), (5, 1), (7, 0)]* y* B0 V# O4 \2 L  z/ h, t
print(G1.number_of_nodes())  # 返回顶点的数量6 V2 J0 {; c8 K) w, S  f% o' x. g
# 9
8 \2 [' X" h- U; \% iprint(G1.number_of_edges())  # 返回边的数量" s  d$ E% [& E. Y6 N
# 5
4 w; U# j5 C5 r4 p8 d( [* J! Xprint(G1[10])  # 返回与指定顶点相邻的所有顶点的属性
1 e2 u6 C  F! U# e# {0: {'weight': 2.7}, 5: {}}  G# l0 ~: S* e
print(G1.adj[10])  # 返回与指定顶点相邻的所有顶点的属性
+ j2 _/ J  @7 t/ c# {0: {'weight': 2.7}, 5: {}}9 x+ s0 A9 z' e+ P# n
print(G1[1][2])  # 返回指定边的属性
8 Z, w( O) v- P9 p8 d1 e# a* @# {'weight': 3.6}
: n2 F, G$ ~+ fprint(G1.adj[1][2])  # 返回指定边的属性2 s9 B- q4 m  ~4 n
# {'weight': 3.6}
# u- f6 b: ?$ X& ?print(G1.degree(10))  # 返回指定顶点的度$ I* ~* y6 l# n0 c- P
# 23 I* n: I) [/ I

& k' @+ e6 t* H+ B) wprint('nx.info:',nx.info(G1))  # 返回图的基本信息
0 E- L2 L1 b, e! ?print('nx.degree:',nx.degree(G1))  # 返回图中各顶点的度
' _7 p; p1 u# Q/ g- O+ F7 e( ]' Hprint('nx.density:',nx.degree_histogram(G1))  # 返回图中度的分布
! W  C7 f+ }' ~. `4 g" a  gprint('nx.pagerank:',nx.pagerank(G1))  # 返回图中各顶点的频率分布/ \) k$ K; Z! @, m6 b) U
$ v: u" W2 f, p4 ?
2 Y. }) e( Y  S6 Y

1 p/ _# T0 g7 w2 P7 _2 ~0 @6 A9 b( z( }
& [; G6 n* h7 ?+ t5 y( }6 C& w- y
2.3 图的属性和方法图的方法( L* P3 W! L# d& P
, J% ]$ d' Z" x, ?: \: u1 A) e
方法                                                说明
; K* \2 c9 \4 V$ W* PG.has_node(n)                                当图 G 中包括顶点 n 时返回 True9 _! G* V* [- L# W, c) U
G.has_edge(u, v)                        当图 G 中包括边 (u,v) 时返回 True5 |& r3 J' G8 n6 j/ ]* q, n
G.number_of_nodes()                        返回 图 G 中的顶点的数量
; V5 n$ x" _3 i! q5 U1 g: R: p, EG.number_of_edges()                        返回 图 G 中的边的数量; t* z8 w* K! {. D$ i2 b( j
G.number_of_selfloops()                返回 图 G 中的自循环边的数量
' i, N1 F+ @$ A  t' ~7 ?3 yG.degree([nbunch, weight])                返回 图 G 中的全部顶点或指定顶点的度
- Z) V. c8 |3 f( GG.selfloop_edges([data, default])        返回 图 G 中的全部的自循环边
& B! Q3 }( @8 W- v% D  N' y) k! mG.subgraph([nodes])                        从图 G1中抽取顶点[nodes]及对应边构成的子图/ ^- e# T; D' S- q' ?
union(G1,G2)                                合并图 G1、G2
& O/ I. ]4 o4 \" R! vnx.info(G)                                        返回图的基本信息( f) a3 @4 {" B: b4 e
nx.degree(G)                                返回图中各顶点的度
4 R2 f8 z* l3 {( T4 a2 |3 P  \6 [2 c) q& Gnx.degree_histogram(G)                返回图中度的分布! ~& ?: M3 V4 y$ ~
nx.pagerank(G)                                返回图中各顶点的频率分布7 A3 K; k  d0 ?" g' F0 t8 W
nx.add_star(G,[nodes],**attr)        向图 G 添加星形网络0 w3 V% `+ q2 H' y! ]
nx.add_path(G,[nodes],**attr)        向图 G 添加一条路径! I7 ~6 a5 u9 P3 N
nx.add_cycle(G,[nodes],**attr)        向图 G 添加闭合路径
  a: J. q, M4 t' I9 w, m) m+ w0 v" d3 y3 t4 L' B$ y0 Y3 T% [
* M+ j; L" y6 l6 D( y% t' j& i
例程:% M2 }; b; E+ K+ L; ^
G1.clear() # 清空图G1
! X" `. K2 j: inx.add_star(G1, [1, 2, 3, 4, 5], weight=1)  # 添加星形网络:以第一个顶点为中心
- M% a/ Q4 L  b6 }  K2 g% D- r# [(1, 2), (1, 3), (1, 4), (1, 5)]  z6 @5 F4 q0 z6 G- R
nx.add_path(G1, [5, 6, 8, 9, 10], weight=2)  # 添加路径:顺序连接 n个节点的 n-1条边
0 B7 Q: {- I( ^. W$ x, T! w! Q# [(5, 6), (6, 8), (8, 9), (9, 10)]! [0 e  @* F" Z' C( T% w! A
nx.add_cycle(G1, [7, 8, 9, 10, 12], weight=3)  # 添加闭合回路:循环连接 n个节点的 n 条边8 K0 t3 t7 W& g! n
# [(7, 8), (7, 12), (8, 9), (9, 10), (10, 12)]
8 @" `; x$ k  v* M: Wprint(G1.nodes)  # 返回所有的顶点 [node1,...]
& b* D0 V0 y9 q# v6 K, w! |. inx.draw_networkx(G1)3 P, `' ?' `6 m  {! C4 A: Z" H
plt.show()
% E& Y- G) U' `5 E: X) n- W% r. v$ W0 X$ T
G2 = G1.subgraph([1, 2, 3, 8, 9, 10])1 `% |" n1 G  @" p4 m) ], w" o
G3 = G1.subgraph([4, 5, 6, 7])
' ^3 T, t+ m1 [  r: m6 ?+ F  LG = nx.union(G2, G3)2 S( D* ?% k/ U' W' ]4 W0 i9 y
print(G.nodes)  # 返回所有的顶点 [node1,...]
& j/ ]  H. ]) {/ v4 ]) F" ]/ X- K1 w# [1, 2, 3, 8, 9, 10, 4, 5, 6, 7]
& Y3 v9 a  {& }0 `+ P; z
# E) H4 T( X8 B3 c/ w# }0 P8 N; o! [' H8 ?- U, e1 b
3、图的绘制与分析3.1 图的绘制
5 m+ P6 H2 N" \5 y; ?, i可视化是图论和网络问题中很重要的内容。NetworkX 在 Matplotlib、Graphviz 等图形工具包的基础上,提供了丰富的绘图功能。
/ Y5 i: W  W& p1 F4 e8 p5 y3 K: s, V; x' E; T
本系列拟对图和网络的可视化作一个专题,在此只简单介绍基于 Matplotlib 的基本绘图函数。基本绘图函数使用字典提供的位置将节点放置在散点图上,或者使用布局函数计算位置。, e& G; \1 V6 O" O( M
- G, Q8 j* D% ^) v+ m
方法                                                                        说明
+ k4 s  ~2 L! w) }. vdraw(G[,pos,ax])                                                基于 Matplotlib 绘制 图 G# y+ D% `  R3 \6 p6 K& ~+ s
draw_networkx(G[, pos, arrows, with_labels])        基于 Matplotlib 绘制 图 G/ f. k% x5 B6 H; I' a
draw_networkx_nodes(G, pos[, nodelist, . . . ])        绘制图 G 的顶点6 Z1 @5 r) ~+ z" _# j1 r4 l
draw_networkx_edges(G, pos[, edgelist, . . . ])        绘制图 G 的边
) J1 |: \" b- F% N* {. kdraw_networkx_labels(G, pos[, labels, . . . ])            绘制顶点的标签0 {1 W. ~* l- T( o' l# j6 ?- G
draw_networkx_edge_labels(G, pos[, . . . ])                绘制边的标签
  i- \1 u* O  w' y
! a; \9 o- `# ^$ I5 b) c* {
( R- B  H5 o% R( C) y其中,nx.draw() 和 nx.draw_networkx() 是最基本的绘图函数,并可以通过自定义函数属性或其它绘图函数设置不同的绘图要求。
8 f- W/ v$ s: I# B% c* A

draw(G, pos=None, ax=None, **kwds)

draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds)


) s# r0 d, e, ~常用的属性定义如下:0 _* x. k; o2 Y3 g
2 c) T7 q$ C/ ]+ _1 V; X! D  ^; L
‘node_size’:指定节点的尺寸大小,默认300. \  d" f  B) Q$ l
‘node_color’:指定节点的颜色,默认红色
" l/ g. ]1 a% i+ a‘node_shape’:节点的形状,默认圆形
2 n7 z; Z: X0 x& L) d'‘alpha’:透明度,默认1.0,不透明
  ^* g- ~* N+ t3 Z7 y; x‘width’:边的宽度,默认1.0
7 L; w) q. }( M+ O6 q# T‘edge_color’:边的颜色,默认黑色
9 d- J& F  n/ v! Z4 q‘style’:边的样式,可选 ‘solid’、‘dashed’、‘dotted’、‘dashdot’
+ c- P) L3 |7 Z% w% _3 j2 O/ ?‘with_labels’:节点是否带标签,默认True  t! `6 n  K" J
‘font_size’:节点标签字体大小,默认12& ?! I% U4 v$ P3 w; `! j  e
‘font_color’:节点标签字体颜色,默认黑色) D) d3 `. ^3 h; f3 m5 F6 a

; g5 f- ^( f7 w( S5 s& f) k- @
8 f! j0 U! }% R* C0 \3.2 图的分析NetwotkX 提供了图论函数对图的结构进行分析
' e5 |2 w) f# k4 G  ?" x* j- B子图# H7 H' X6 ^# |" @! F
连通子图7 H  W- \. g$ A% H% v! X, h

# R& @- C6 L; f/ R: E; E$ o3 m7 \- Y5 K" t4 t. }' C# L8 \

% i. w7 B) N$ X; v% @& I
0 l* o) Y/ `5 X# I+ E& Z2 }' N* B* I7 Y  f# w) g: u& ^





欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5