networkx 有向图强连通_基于networkx分析Louvain算法的社团网络划分
圖論之-Python NetworkX 入門
1:圖論概述
1.1圖論基本概念
1圖
一個圖G = (V, E)由一些點及點之間的連線(稱為邊)構成,V、E分別計G的點集合和邊集合。在圖的概念中,點的空間位置,邊的區直長短都無關緊要,重要的是其中有幾個點以及那些點之間有變相連。
圖1:圖示例
2有向圖和無向圖
最基本的圖通常被定義為“無向圖”,與之對應的則被稱為“有向圖”。兩者唯一的區別在于,有向圖中的邊是有方向性的。
圖2:有向圖和無向圖
注:上圖左邊為無向圖,右邊為有向圖。黑色加粗部分表示邊的方向。比如:1—>2便是邊是1到2這個方向。
3圖的度
度是相對于圖中點的概念,圖中任意一點v的度是指:與v相連的邊的條數。在有向圖中與頂點v出關聯的邊的數目稱為出度,與頂點v入關聯的邊的數目稱為入度。比如上圖2:左邊無向圖頂點2的度是3.右邊有向圖點點2的出度是2,入度是1.
4圖的連通性
在圖G中,若頂點u,v之間有路(即找到有u到v之間相連的邊)則稱u,v連通。若G的任何兩點之間有路,則稱G是連通圖。G的極大連通子圖稱為連通分支。如果連通圖是有向圖則稱G是強連通的。
5圖的最短路徑
在圖上任取兩頂點,分別作為起點和終點,我們可以規劃許多條由起點到終點的路線。不會來來回回繞圈子、不會重復經過同一個點和同一條邊的路線,就是一條“路徑”,這些路徑中經過頂點最少的那個路徑就是最短路徑。
6圖的簡單路徑
如果路徑上的各頂點均不互相重復,稱這樣的路徑為簡單路徑。如果路徑上的第一個頂點與最后一個頂點重合,這樣的路徑稱為回路(cycle)或環或圈。比如下圖中:(1,2,3,4,5,1),(1,2,3,1),(1,3,4,5,1)等都是簡單路徑。
圖3:簡單路徑
7圖的偏心距(eccentricity)
一個節點的偏心距就是這個節點到其他節點的所有節點的最短路徑的最大值。
8圖的直徑和半徑
圖的所有節點偏心距的最大值就是圖的直徑,最小值就是半徑。
9圖的緊密中心性(closeness)
在圖論中,緊密度是圖中一個節點的中心性度量。比其他節點更“淺”(也就是說,有更短的測地距離)的節點有更高的緊密度。在網絡分析中,緊密度傾向于表示最短路徑長度,因為這樣會有更多的中心節點賦予更高的值,而且通常與其他度量(比如:度)相聯系。緊密度是中心性的一種復雜度量。它被定義為節點v到其它可達節點的平均測地距離(比如:最短路徑):
其中當n>=2是從v出發在網絡中連通部分V的大小。接近中心性需要考量每個結點到其它結點的最短路的平均長度。也就是說,對于一個結點而言,它距離其它結點越近,那么它的中心度越高。一般來說,那種需要讓盡可能多的人使用的設施,它的接近中心度一般是比較高的。
10圖的介數中心性(Betweenness Centrality)
對于n各節點的圖G=(V, E),節點v的介數CB(v)按如下方式計算:
對于每對節點(s, t),計算他們之間所有的最短路徑;
對于每對節點(s, t),通過判斷(here, 節點v)求出它在最短路徑上的部分;
對每對節點(s, t)求出的部分進行累加
公式表示為:
其中:σst是s到t的最短路徑數,σst()是s到t的最短路徑中經過v的數量。它可以除以不包括節點v的節點數量(對于無向圖是(n-1)(n-2)/2有向圖是(n-1)(n-2)類歸一化。)中介中心性指的是一個結點擔任其它兩個結點之間最短路的橋梁的次數。一個結點充當“中介”的次數越高,它的中介中心度就越大。
11圖的度中心性
度中心性(Degree Centrality)是在網絡分析中刻畫節點中心性(Centrality)的最直接度量指標。一個節點的節點度越大就意味著這個節點的度中心性越高,該節點在網絡中就越重要。
1.2圖論基本算法
1圖遍歷之BFS算法(廣度優先搜索)
算法步驟:
首先選擇一個頂點作為起始節點,并將其染成灰色,其余結點為白色。
將起始結點放入隊列中。
從隊列首部選出一個頂點,并找出所有與之鄰接的結點,將找到的鄰接結點放入隊列尾部,將已訪問過結點涂成黑色,沒訪問過的結點是白色。如果頂點的顏色是灰色,表示已經發現并且放入了隊列,如果頂點的顏色是白色,表示還沒有發現?。
按照同樣的方法處理隊列中的下一個結點。
例如:下圖
圖:BFS搜索
從上圖節點1開始搜索,染成灰色,其余白色。此時隊列中只有節點{1}
搜索1的鄰居節點2, 3,此時1出隊染成黑色表示已經訪問,23入隊{2, 3}
搜索2的鄰居節點3, 4,節點3已經在隊列所以2出隊染成黑色添加4進入隊列{3, 4}
搜索3的鄰居節點2,4,節點2已經變黑表示已經訪問,節點3出隊變成黑色4此時就在隊列{4}
搜索4的鄰居節點1,節點1已變成黑色。所以4出隊變成黑色。隊列為空。
此時1, 2, 3, 4, 都已經變成黑色。還剩節點5,再從5開始搜索,結束。
2圖遍歷之DFS算法(深度優先搜索)
算法步驟:
選擇起始頂點涂成灰色,表示還未訪問;
從該頂點的鄰接頂點中選擇一個,繼續這個過程(即再尋找鄰接結點的鄰接結點),一直深入下去,直到一個頂點沒有鄰接結點了,涂黑它,表示訪問過了;
回溯到這個涂黑頂點的上一層頂點,再找這個上一層頂點的其余鄰接結點,繼續如上操作,如果所有鄰接結點往下都訪問過了,就把自己涂黑,再回溯到更上一層;
上一層繼續做如上操作,知道所有頂點都訪問過。
實例:用下圖作為說明
圖:DFS搜索
從節點1開始依次訪問1à2à 3之后終止于節點3;
從節點3回溯到節點2,從2à5終止于節點5;
從節點5回溯到2終止于2;
從節點2回溯到1并終止于1;
從頂點4開始訪問終止于4.
3Python實現BFS和DFS(基于無向圖)。
class Mygraph(object):
def __init__(self, *args, **kwargs):
self.node_neighbors = {}
self.visited = {}
def nodes(self):
return self.node_neighbors
def add_node(self, node):
if not node in self.nodes():
self.node_neighbors = []
def add_nodes(self, nodelist):
for node in nodelist:
self.add_node(node)
def add_edge(self, edge):
u, v = edge
if? u not in self.nodes():
self.node_neighbors[u] = []
if? v not in self.nodes():
self.node_neighbors[v] = []
if (v not in self.node_neighbors[u]) and (u not in self.node_neighbors[v]):
self.node_neighbors[u].append(v)
if u != v:
self.node_neighbors[v].append(u)
def add_edges(self, edges):
for edge in edges:
self.add_edge(edge)
def depth_first_search(self, root=None):
order = []
def dfs(node):
self.visited[node] = True
order.append(node)
for n in self.node_neighbors[node]:
if not n in self.visited:
dfs(n)
if root:
dfs(root)
for node in self.nodes():
if not node in self.visited:
dfs(node)
return order
def breath_first_search(self, root=None):
queue = []
order = []
def bfs():
while len(queue)>0:
node = queue.pop(0)
self.visited[node] = True
for n in self.node_neighbors[node]:
if (not n in self.visited) and (not n in queue):
queue.append(n)
order.append(n)
if root:
queue.append(root)
order.append(root)
bfs()
for node in self.nodes():
if not node in self.visited:
queue.append(node)
order.append(node)
bfs()
return order
if __name__=='__main__':
edges = [(1, 2), (1, 3), (2, 3),
(2, 5), (3, 4), (4, 2),
(4, 5), (5, 3)]
G = Mygraph()
G.add_edges(edges)
print(G.nodes())
print("廣度優先遍歷:")
bfs_order = G.breath_first_search(1)
print(bfs_order)
G = Mygraph()
G.add_edges(edges)
dfs_order = G.depth_first_search(1)
print("深度優先遍歷:")
print(dfs_order)
注:為什么創建圖寫了兩遍,因為只寫一次,進行廣度優先訪問之后,有些會被標記為TRUE,會影響后面深度訪問結果。
2:NetworkX入門
2.1Networkx概述與安裝
1概述
NetworkX是一款Python的軟件包,用于創造、操作復雜網絡,以及學習復雜網絡的結構、動力學及其功能。 有了NetworkX你就可以用標準或者不標準的數據格式加載或者存儲網絡,它可以產生許多種類的隨機網絡或經典網絡,也可以分析網絡結構,建立網絡模型,設計新的網絡算法,繪制網絡等等
2安裝
方式一:pip install networkx就行
方式二:安裝Anaconda,本身已經集成了這個包,十分方便。
2.2Networkx使用
1創建圖添加節點和邊
G = nx.Graph() # 創建無向圖(nx.DiGraph() 創建有向圖)
G.add_node(0) # 添加一個節點
G.add_nodes_from([1, 2])# 一次添加多個節點
G.add_edge(0, 1) # 添加一條邊
G.add_edge(2, 3) # 如果邊的節點已經存在,直接覆蓋
G.add_edge(4, 5) # 如果邊的節點不存在,則添加新節點
G.add_edges_from([(2, 1), (5, 1), (0, 4), (3, 4)]) #添加多條邊基于上面添加的節點和邊繪制有向圖和無向圖如下:
注:左圖表示有向圖,黑色加粗部分表示邊的方向。右圖表示無向圖沒有方向之分。圖的顯示還有兩個比較好用的工具就是Cytoscape和Gephi也比較好用,顯示圖像方便又美觀,其中Cytoscape可以讀取CSV文件,可以對圖進行拖拽。感興趣的朋友可以研究一下。
2求圖的常用屬性
讀取CSV文件獲取圖的邊集合列表
部分原始數據如圖:
計算圖的各種屬性
整體圖,看到所有人都是有聯系的,由于人物比較多,所以圖顯示不出具體的效果。
圖:整體關系圖
各個節點的度,也就是和其他節點連接的數量,越多表示人物在劇中的重要程度。從列表看出度數大的就是劇中的主角了。
圖:各個節點的度
節點的偏心距:任意一個節點到其他節點的最短路徑的最大值,可以看到基本上任意兩個人通過兩個三個人就能找到連通路徑,所以居中人物的關系還是比較密的。
圖:各個節點的偏心距
查看節點到另一節點或其他節點的最短路徑
查看節點到另一節點或其他節點的最短路徑的長度
緊密中心性:越大說明中心越強。
介數中心性:
上代碼:
import re
import networkx as nx
import matplotlib.pyplot as plt
def create_graph():
G = nx.Graph()
# G = nx.DiGraph()
G.add_node(0) # 添加一個節點
G.add_nodes_from([1, 2])# 一次添加多個節點
G.add_edge(0, 1) # 添加一條邊
G.add_edge(2, 3) # 如果邊的節點已經存在,直接覆蓋
G.add_edge(4, 5) # 如果邊的節點不存在,則添加新節點
G.add_edges_from([(2, 1), (5, 1), (0, 4), (3, 4)]) #添加多條邊
nx.draw(G, pos=nx.spring_layout(G), with_labels=True)
plt.show()
def read_nodes(filename):
'''讀取文件,獲取邊列表'''
edges_list = []
with open(filename, 'r') as f:
while True:
line = f.readline()
if line:
line = re.sub('\r\n', '', line)
lines = line.split(',')
edges_list.append((lines[0], lines[1]))
edges_list.append((lines[1], lines[0]))
else:
break
return edges_list
‘’’注:因為networkx中求最大連通子圖的實現都是基于有向圖的,所以在讀取數據的時候,添加邊的時候都是雙向的,這樣保證求出來的最大連通子圖和無向圖是一樣的。’’’
def get_graph_attr(edges):
# 1根據邊的列表創建無向圖
G = nx.DiGraph()
G.add_edges_from(edges)
# 2 查看圖中的節點有多少個
nodes = G.nodes()
print(len(nodes)) # 107
# 2 求無向圖的最大連通子圖
max_component = max(nx.strongly_connected_component_subgraphs(G), key=len)# 最大連通子圖
print(len(max_component.nodes())) # 107最大連通子圖就是本身
# 3 將圖轉換為無向圖
G = nx.to_undirected(max_component)
# 4 計算圖中節點的度,按大小排序
degrees = G.degree() # 所有節點的度
print(sorted(degrees, key=lambda x:x[1], reverse=True))
# 5 計算圖的偏心距和直徑以及半徑
eccdis = nx.eccentricity(G) # 偏心距
print(eccdis)
diamter = max(eccdis.values()) # 直徑
radius = min(eccdis.values()) # 半徑
print(diamter, radius) # 6, 3
#5 計算圖中節點的最短路徑
path = nx.shortest_path(G, source='Jon')# 查看誰到誰的最短路徑
print(path)
path_length = nx.shortest_path_length(G, source='Jon')# 查看最短路徑的長度
print(path_length)
#6 計算圖中節點的緊密中心性
close = nx.closeness_centrality(G)#緊密中心性
print(close)
# 7 介數中心性
jie = nx.betweenness_centrality(G)
print(jie)
if __name__=='__main__':
filename = './inputdata/stormofswords.csv'
edges = read_nodes(filename)
get_graph_attr(edges)
3:Louvain算法+NetworkX之社團劃分實例
3.1Louvain算法原理
Louvain算法是基于模塊度的社區發現算法,該算法在效率和效果上都表現較好,并且能夠發現層次性的社區結構,其優化目標是最大化整個社區網絡的模塊度。
模塊度:
模塊度是評估一個社區網絡劃分好壞的度量方法,它的物理含義是社區內節點的連邊數與隨機情況下的邊數只差,它的取值范圍是?[?1/2,1)其公式如下:
其中,Aij節點i和節點j之間邊的權重,網絡不是帶權圖時,所有邊的權重可以看做是1;ki=∑jAij表示所有與節點i相連的邊的權重之和(度數);ci表示節點i所屬的社區;m=12∑ijAij表示所有邊的權重之和(邊的數目)。公式中Aij?kikj2m=Aij?kikj2m,節點j連接到任意一個節點的概率是kj2m,現在節點i有ki的度數,因此在隨機情況下節點i與j的邊為kikj2m.
算法步驟:
1)將圖中的每個節點看成一個獨立的社區,次數社區的數目與節點個數相同;
2)對每個節點i,依次嘗試把節點i分配到其每個鄰居節點所在的社區,計算分配前與分配后的模塊度變化ΔQ,并記錄ΔQ最大的那個鄰居節點,如果maxΔQ>0,則把節點i分配ΔQ最大的那個鄰居節點所在的社區,否則保持不變;
3)重復2),直到所有節點的所屬社區不再變化;
4)對圖進行壓縮,將所有在同一個社區的節點壓縮成一個新節點,社區內節點之間的邊的權重轉化為新節點的環的權重,社區間的邊權重轉化為新節點間的邊權重;
5)重復1)直到整個圖的模塊度不再發生變化。
圖:算法過程圖
3.2社團劃分實踐
基于2.2權利的游戲的任務關系網絡進行Louvain算法社團劃分。算法源碼參考2可以找到。這里就直接用了看下效果。
總共107個角色,劃分了6個社團。
參考:
https://blog..net/wizard_wsq/article/details/50628009
https://www..com/fengfenggirl/p/louvain.html
https://www.quora.com/Is-there-a-simple-explanation-of-the-Louvain-Method-of-community-detectio
https://blog..net/xuanyuansen/article/details/68941507
https://www..com/allanspark/p/4197980.html
總結
以上是生活随笔為你收集整理的networkx 有向图强连通_基于networkx分析Louvain算法的社团网络划分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何查询oracle的共享内存,[201
- 下一篇: 解决 | 此数据库文件跟当前sql se