寫在前面:城市計算研究中經常涉及到圖論
的相關知識,而且常常面對某些術語時,根本不知道在說什么.最近接觸了NetworkX這個graph處理工具,發現這個工具已經解決絕大部分的圖論
問題(也許只是我自己認為的,沒有證據證明),所以把這個工具的使用學習下,順便學習圖論
的相關知識.
創建一個圖
import networkx as nx G = nx.Graph()
節點
一次添加一個節點 G.add_node(1) 添加一個節點列表 G.add_nodes_from([2, 3])
邊
可以通過一次添加一條邊來增長 G.add_edge(1, 2) e = (2, 3) G.add_edge(*e) # unpack edge tuple*
也可以通過添加邊列表 G.add_edges_from([(1, 2), (1, 3)])
刪除圖中所有節點和邊
G.clear()
我們添加新的節點/邊,並且NetworkX會自動的忽略任何已經存在的節點。
G.add_edges_from([(1, 2), (1, 3)]) G.add_node(1) G.add_edge(1, 2) G.add_node("spam") # adds node "spam"
G.add_nodes_from("spam") # adds 4 nodes: 's', 'p', 'a', 'm'
G.add_edge(3, 'm')
在這個階段,圖形G
由8個節點和3個邊組成,如下所示:
>>> G.number_of_nodes() 8
>>> G.number_of_edges() 3
我們可以檢查節點和邊。四個基本圖形屬性:G.nodes
,G.edges
,G.adj
和G.degree
。這些是節點,邊,鄰居(鄰接點)和圖中節點的程度集的視圖。
>>> list(G.nodes) ['a', 1, 2, 3, 'spam', 'm', 'p', 's'] >>> list(G.edges) [(1, 2), (1, 3), (3, 'm')] >>> list(G.adj[1]) # or list(G.neighbors(1))
[2, 3] >>> G.degree[1] # the number of edges incident to 1
2
可以以類似於添加的方式從圖中移除節點和邊。使用方法 Graph.remove_node()
,Graph.remove_nodes_from()
, Graph.remove_edge()
和 Graph.remove_edges_from()
,如
>>> G.remove_node(2) >>> G.remove_nodes_from("spam") >>> list(G.nodes) [1, 3, 'spam'] >>> G.remove_edge(1, 3)
通過實例化其中一個圖形類來創建圖形結構時,可以使用多種格式指定數據
>>> G.add_edge(1, 2) >>> H = nx.DiGraph(G) # create a DiGraph using the connections from G
>>> list(H.edges()) [(1, 2), (2, 1)] >>> edgelist = [(0, 1), (1, 2), (2, 3)] >>> H = nx.Graph(edgelist)
訪問邊和節點鄰居
除了視圖之外Graph.edges()
,Graph.adj()
還可以使用下標符號來訪問邊和鄰居。
>>> G[1] # same as G.adj[1]
AtlasView({2: {}}) >>> G[1][2] {} >>> G.edges[1, 2] {}
如果邊已經存在,可以使用下標符號來獲取/設置邊的屬性。
>>> G.add_edge(1, 3) >>> G[1][3]['color'] = "blue"
>>> G.edges[1, 2]['color'] = "red"
所有(節點,鄰接節點)的快速查詢都是使用 G.adjacency()
或G.adj.items()完成的
。請注意,對於無向圖,鄰接迭代會將每個邊看兩次。
>>> 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('(%d, %d, %.3f)' % (n, nbr, wt)) (1, 2, 0.125) (2, 1, 0.125) (3, 4, 0.375) (4, 3, 0.375)
通過邊屬性可以方便地訪問所有的邊。
>>> for (u, v, wt) in FG.edges.data('weight'): ... if wt < 0.5: print('(%d, %d, %.3f)' % (u, v, wt)) (1, 2, 0.125) (3, 4, 0.375)
將屬性添加到圖形,節點和邊
屬性(如權重,標簽,顏色或任何您喜歡的Python對象)可以附加到圖形,節點或邊上。
每個圖形,節點和邊都可以在關聯的屬性字典中保存鍵/值屬性對(鍵必須是可散列的)。默認情況下,這些都是空的,但屬性可以使用添加或更改add_edge
,add_node
或命名的屬性字典的直接操作G.graph
,G.nodes
和 G.edges
一個圖G。
圖形屬性
創建新圖形時分配圖形屬性
>>> G = nx.Graph(day="Friday") >>> G.graph {'day': 'Friday'}
或者也可以修改屬性
>>> G.graph['day'] = "Monday"
>>> G.graph {'day': 'Monday'}
節點屬性
添加節點屬性使用add_node()
,add_nodes_from()
或G.nodes
>>> G.add_node(1, time='5pm') >>> G.add_nodes_from([3], time='2pm') >>> G.nodes[1] {'time': '5pm'} >>> G.nodes[1]['room'] = 714
>>> G.nodes.data() NodeDataView({1: {'room': 714, 'time': '5pm'}, 3: {'time': '2pm'}})
邊屬性
添加/更改邊使用的屬性add_edge()
,add_edges_from()
或標符號。
>>> 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
有向圖:DiGraph()
DiGraph類提供特定於有向邊的附加屬性,例如DiGraph.out_edges()
,DiGraph.in_degree()
,DiGraph.predecessors()
,DiGraph.successors()
等。為了使算法能夠輕松地處理這兩個類, neighbor()
的功能等同於successors()
,而degree
會報告in_degree
和out_degree
的總和,即使有時可能會感覺不一致
dg = nx.DiGraph() nodes1 = [ ('Variable', {'name': 'avariable', 'table': 'tablename'}), ('Select', {'conditions': {'pro_code': 44}}), ('GroupBy', {'varname': 'gender'}), ('Mean', {}), ('Which1', {'level': 1}), ('Decimal1', {'place': 1}), ] nodes2 = [ ('Which1', {'level': 2}), ('Decimal2', {'place': 1}), ] nodes3 = [ ('Add', {}) ] dg.add_nodes_from(nodes1) dg.add_nodes_from(nodes2) dg.add_nodes_from(nodes3) dg.add_edges_from([ ('Variable', 'Select'), ('Select', 'GroupBy'), ('GroupBy', 'Mean'), ('Mean', 'Which1'), ('Mean', 'Which2'), ('Which1', 'Decimal1'), ('Which2', 'Decimal2'), ('Decimal1', 'Add'), ('Decimal2', 'Add'), ]) nx.draw(dg, with_labels=True)