在複雜網絡系統中,理解內部結構是制定策略的關鍵。社群偵測演算法,如 Girvan-Newman,提供自頂向下的視角,透過移除關鍵橋樑來揭示宏觀社群邊界。與此同時,團體分析則採自底向上的觀點,專注於識別凝聚力最強的核心子群體。結合這兩種方法,分析師能從宏觀與微觀層面完整洞察網絡結構,為組織分析、市場區隔或系統韌性評估提供數據基礎。
Girvan-Newman 社群劃分的視覺化與解讀
本章節將聚焦於 Girvan-Newman 演算法在 Zachary 空手道網路上的應用,並透過視覺化來呈現其第一次分割所產生的兩個社群。我們將運用與先前相同的繪圖策略,以區分社群內部與外部的連接,並解讀視覺化結果。
視覺化程式碼實踐:呈現兩個社群
Girvan-Newman 演算法的第一次分割通常會將網路劃分為兩個主要的社群。為了清晰地展示這一結果,我們將採用分層繪製的方式:
-
準備邊列表與顏色:
- 外部邊 (External Edges):
- 如前所述,我們首先識別出連接這兩個新社群的邊。這些邊的
'community'屬性被標記為 0。 external = [(v, w) for v, w in G_karate.edges if G_karate.edges[v, w]['community'] == 0]創建了外部邊的列表。
- 如前所述,我們首先識別出連接這兩個新社群的邊。這些邊的
- 內部邊 (Internal Edges):
- 接著,我們識別出屬於兩個獨立社群內部的邊。它們的
'community'屬性將是 1 或 2。 internal = [(v, w) for v, w in G_karate.edges if G_karate.edges[v, w]['community'] > 0]創建了內部邊的列表。
- 接著,我們識別出屬於兩個獨立社群內部的邊。它們的
- 內部邊顏色:
internal_color = [get_color(G_karate.edges[e]['community']) for e in internal]為每個內部邊生成對應其所屬社群的顏色。由於 Girvan-Newman 的第一次分割只產生兩個社群,get_color()函數將會生成兩種不同的顏色。
- 外部邊 (External Edges):
-
繪製圖形:
- 繪製外部邊:
nx.draw_networkx(G_karate, pos=karate_pos, node_size=0, edgelist=external, edge_color="#333333", with_labels=False)- 此步驟繪製連接兩個主要社群的邊。它們以深灰色顯示,線條較細,且不顯示節點,以突出社群結構。
- 繪製節點與內部邊:
nx.draw_networkx(G_karate, pos=karate_pos, node_color=node_color, edgelist=internal, edge_color=internal_color)- 此步驟繪製節點和社群內部的邊。
node_color=node_color為節點賦予根據其所屬社群(由set_node_community設定)生成的顏色。edgelist=internal和edge_color=internal_color確保內部邊以與其所屬社群相符的顏色繪製。
- 繪製外部邊:
視覺化結果與解讀
繪製完成的圖形將清晰地展示 Zachary 空手道網路被 Girvan-Newman 演算法劃分為兩個社群的結果:
- 兩個主要社群:
- 圖形會顯示出兩個明顯不同的節點群集,每個群集代表一個社群。
- 節點的顏色和內部邊的顏色將一致地反映這兩個社群的劃分。
- 連接的橋樑:
- 外部的灰色邊線將這兩個社群連接起來。這些邊代表了 Girvan-Newman 演算法在該階段識別出的「橋樑」或「關鍵連接」。
- 觀察這些外部邊的數量和位置,可以了解兩個主要社群之間的聯繫程度。
- 與現實的對應:
- Girvan-Newman 演算法的第一次分割結果,通常會捕捉到 Zachary 空手道組織分裂的兩個主要派系。這兩個社群的劃分,反映了當時組織內部的權力鬥爭和派系形成。
看圖說話:
此圖示總結了「Girvan-Newman 社群劃分的視覺化與解讀」的內容,重點在於展示 Girvan-Newman 演算法在 Zachary 空手道網路上的第一次分割結果,並透過視覺化進行呈現與解讀。流程開頭首先聚焦於「Girvan-Newman 社群劃分的視覺化與解讀」,透過「分割」結構,詳細闡述了「視覺化程式碼實踐:呈現兩個社群」(概述了「準備邊列表與顏色」,並描述了「繪製圖形 (分層)」的過程),接著探討了「視覺化結果與解讀」(指出了「兩個主要社群」,描述了「連接的橋樑」,並說明了「與現實的對應」),最後以「總結與展望」作結,對比了「演算法的視角」,並指出其「為後續分析奠定基礎」。
迭代式社群劃分與團體結構分析
本章節將延續 Girvan-Newman 演算法的討論,探討如何控制社群劃分的精細程度,並引入另一種重要的網路結構分析概念——團體 (Cliques)。
精確控制社群數量
Girvan-Newman 演算法的迭代特性允許我們在不同階段停止分割,從而獲得不同數量的社群。
- 迭代器與
itertools.islice():nxcom.girvan_newman()函數返回的迭代器會逐步細分網路。每一次迭代都代表了一次社群的進一步劃分。- 為了獲取特定數量的社群,我們可以利用 Python 的
itertools.islice()函數來精確地從迭代器中提取所需的分割結果。
- 範例:獲取四個社群:
result = nxcom.girvan_newman(G_karate):獲取 Girvan-Newman 演算法的迭代器。communities = next(itertools.islice(result, 2, 3)):itertools.islice(result, 2, 3)會從迭代器result中跳過前兩個元素(即前兩次分割),然後取第三個元素。- 在 Girvan-Newman 演算法中,第一次分割通常產生 2 個社群,第二次分割(迭代器中的第三個元素)則會將這 2 個社群進一步細分,從而產生 4 個社群。
- 視覺化:
- 獲取到包含四個社群的分割後,可以使用與先前相同的視覺化程式碼來呈現結果。
- 圖形將顯示網路被劃分為四個更小的社群,這些社群是先前兩個社群的子集。
- 後續分割:
- 迭代器
result中後續的值將會進一步細分現有的社群,產生更多、更小的社群群集。
- 迭代器
團體 (Cliques) 的識別與分析
團體是網路中最密集、連接最緊密的子結構之一。
- 團體的定義:
- 團體 (Clique) 是指網路中一組節點,其中任意兩個節點之間都存在直接連接。換句話說,團體是一個完全連通的子圖。
- 團體的意義:
- 團體代表了網路中最緊密的關係或互動。
- 團體中的節點通常屬於同一個社群,團體常常構成社群的核心。
- 識別團體有助於揭示網路底層的結構,特別是與關聯網路 (affiliation networks) 相關的結構。
- 關聯網路與單模網路的轉換:
- 在關聯網路中,節點可能代表個人,邊代表個人與某個群體(如社團、活動)的關聯。
- 透過投影 (projection) 的方式,可以將關聯網路轉換為單模網路(例如,只有個人節點的網路)。在這種轉換過程中,如果某個群體中的所有成員都被移除,則該群體中的成員之間會被連接成一個團體。
- NetworkX 的團體查找功能:
- NetworkX 提供了
nx.find_cliques()函數來查找網路中的所有團體。 - 此函數返回一個迭代器,其中每個元素都是一個團體(節點列表)。
cliques = list(nx.find_cliques(G_karate)):將 Zachary 空手道網路中的所有團體查找出來,並轉換為列表。- 範例輸出顯示了找到的一些團體,例如
[0, 1, 17]和[0, 1, 2, 3, 13]。
- NetworkX 提供了
最大團體 (Maximal Clique) 的識別與視覺化
- 最大團體:
- 在所有團體中,最大團體 (Maximal Clique) 是指那個包含最多節點的團體。它代表了網路中最密集的部分。
- 查找最大團體:
max_clique = max(cliques, key=len):利用 Python 的max()函數,並指定key=len,可以從團體列表中找到長度(節點數量)最大的團體。- 範例輸出顯示 Zachary 空手道網路的最大團體是
[0, 1, 2, 3, 13],包含 5 個節點。
- 視覺化最大團體:
- 為了視覺化最大團體,我們可以將屬於該團體的節點標記為特定顏色(例如,鮮豔的顏色),而其他節點則用較為柔和的顏色顯示。
- 程式碼片段展示了如何設置節點顏色:
- 首先,將所有節點的顏色初始化為灰色
(0.5, 0.5, 0.5)。 - 然後,遍歷節點,如果節點屬於最大團體
max_clique,則將其顏色更改為醒目的顏色。
- 首先,將所有節點的顏色初始化為灰色
import networkx as nx
import networkx.community as nxcom
import matplotlib.pyplot as plt
import itertools
# --- 創建 Zachary 空手道網路 ---
G_karate_demo = nx.karate_club_graph()
# --- Girvan-Newman 迭代式社群劃分 (獲取四個社群) ---
communities_gn_4 = []
print("\n--- 使用 Girvan-Newman 演算法獲取四個社群 ---")
try:
girvan_newman_iterator = nxcom.girvan_newman(G_karate_demo)
# 使用 itertools.islice 跳過前兩個分割,獲取第三個分割 (通常產生 4 個社群)
# islice(iterator, start, stop) - stop 是 exclusive
communities_gn_4 = next(itertools.islice(girvan_newman_iterator, 2, 3))
num_communities_gn_4 = len(communities_gn_4)
print(f"Girvan-Newman 迭代 3 得到的社群數量: {num_communities_gn_4}")
print("四個社群的大小:")
for i, comm in enumerate(communities_gn_4):
print(f" 社群 {i+1}: {len(comm)} 個節點")
except Exception as e:
print(f"獲取四個社群時發生錯誤: {e}")
# --- 團體 (Cliques) 查找與分析 ---
print("\n--- 查找團體 (Cliques) ---")
cliques = []
max_clique = []
try:
# 查找所有團體
cliques = list(nx.find_cliques(G_karate_demo))
print(f"找到的團體總數: {len(cliques)}")
# 查找最大團體
if cliques:
max_clique = max(cliques, key=len)
print(f"最大團體 (Maximal Clique) 包含 {len(max_clique)} 個節點: {max_clique}")
else:
print("網路中未找到任何團體。")
except Exception as e:
print(f"查找團體時發生錯誤: {e}")
# --- 視覺化輔助函數 (沿用前述定義) ---
def set_node_community(G, communities_list):
if not communities_list: return
for c, nodes_in_community in enumerate(communities_list):
for node in nodes_in_community:
G.nodes[node]['community'] = c + 1
def set_edge_community(G):
for u, v in G.edges():
if 'community' in G.nodes[u] and 'community' in G.nodes[v]:
if G.nodes[u]['community'] == G.nodes[v]['community']:
G.edges[u, v]['community'] = G.nodes[u]['community']
else:
G.edges[u, v]['community'] = 0
else:
pass
def get_color(community_id, n_communities, low=0.1, high=0.9):
if community_id == 0: return (0.5, 0.5, 0.5) # 灰色
if n_communities <= 1: return (0.8, 0.2, 0.2)
normalized_community_id = (community_id - 1) / (n_communities - 1)
return plt.cm.viridis(normalized_community_id)
# --- 視覺化 Girvan-Newman 四個社群 ---
if communities_gn_4 and G_karate_demo.number_of_nodes() > 0:
print("\n--- 繪製 Girvan-Newman 四個社群結構圖 ---")
# 設置節點和邊的社群屬性
set_node_community(G_karate_demo, communities_gn_4)
set_edge_community(G_karate_demo)
# 準備節點顏色
n_communities_gn_4 = len(communities_gn_4)
node_colors_gn_4 = []
for node in G_karate_demo.nodes():
community_id = G_karate_demo.nodes[node].get('community', 0)
node_colors_gn_4.append(get_color(community_id, n_communities_gn_4))
# 準備邊列表與顏色
external_edges_gn_4 = []
internal_edges_gn_4 = []
internal_edge_colors_gn_4 = []
for u, v, d in G_karate_demo.edges(data=True):
community_id = d.get('community', 0)
if community_id == 0:
external_edges_gn_4.append((u, v))
else:
internal_edges_gn_4.append((u, v))
internal_edge_colors_gn_4.append(get_color(community_id, n_communities_gn_4))
# 計算佈局
karate_pos = nx.spring_layout(G_karate_demo, seed=42, k=0.3)
plt.figure(figsize=(10, 8))
# 繪製外部邊
nx.draw_networkx(
G_karate_demo, pos=karate_pos, node_size=0,
edgelist=external_edges_gn_4, edge_color="#333333", width=0.5, alpha=0.4, style='dashed'
)
# 繪製節點和內部邊
nx.draw_networkx(
G_karate_demo, pos=karate_pos,
node_color=node_colors_gn_4, node_size=300, alpha=0.9,
edgelist=internal_edges_gn_4, edge_color=internal_edge_colors_gn_4, width=1.5, alpha=0.7
)
nx.draw_networkx_labels(G_karate_demo, karate_pos, font_size=10, font_weight='bold')
plt.title("Zachary Karate Club Network - Girvan-Newman Communities (4 Communities)", fontsize=16)
plt.axis('off')
plt.show()
else:
print("\n無法繪製四個社群的視覺化,因為社群偵測失敗或網路為空。")
# --- 視覺化最大團體 ---
if max_clique and G_karate_demo.number_of_nodes() > 0:
print("\n--- 視覺化最大團體 (Maximal Clique) ---")
# 設置節點顏色:最大團體節點為醒目顏色,其他為灰色
node_colors_max_clique = [(0.5, 0.5, 0.5) for _ in G_karate_demo.nodes()] # 預設灰色
max_clique_nodes = set(max_clique)
for i, v in enumerate(G_karate_demo.nodes()):
if v in max_clique_nodes:
node_colors_max_clique[i] = (0.9, 0.2, 0.2) # 醒目紅色
plt.figure(figsize=(10, 8))
# 繪製網路,強調最大團體節點
nx.draw_networkx(
G_karate_demo, pos=karate_pos,
node_color=node_colors_max_clique, node_size=300, alpha=0.9,
edge_color="#333333", width=0.5, alpha=0.4, style='dashed' # 繪製所有邊
)
nx.draw_networkx_labels(G_karate_demo, karate_pos, font_size=10, font_weight='bold')
plt.title("Zachary Karate Club Network - Maximal Clique Highlighted", fontsize=16)
plt.axis('off')
plt.show()
print("最大團體視覺化完成,標示出網路中最密集連接的節點群組。")
else:
print("\n無法視覺化最大團體,因為未找到團體或網路為空。")
@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100
start
:迭代式社群劃分與團體結構分析;:精確控制社群數量;
note right
Girvan-Newman 迭代特性
使用 itertools.islice() 提取分割
範例: 獲取 4 個社群 (第三個分割)
視覺化: 顯示更細分的社群結構
end note
:團體 (Cliques) 的識別與分析;
note right
團體定義: 完全連通的節點子集
團體意義: 網路最密集區域, 社群核心
關聯網路轉換: 投影機制
NetworkX 函數: nx.find_cliques()
結果: 迭代器 (所有團體)
end note
:最大團體 (Maximal Clique) 的識別與視覺化;
note right
最大團體: 包含最多節點的團體
查找方法: max(cliques, key=len)
視覺化: 突出顯示最大團體節點
end note
:總結與展望;
note right
Girvan-Newman 的靈活性
團體分析的價值
為後續網路結構分析奠定基礎
end note
stop
@enduml
看圖說話:
此圖示總結了「迭代式社群劃分與團體結構分析」的內容,重點在於探討如何精確控制 Girvan-Newman 演算法的社群劃分數量,以及引入團體 (Cliques) 的概念進行網路結構分析。流程開頭首先聚焦於「迭代式社群劃分與團體結構分析」,透過「分割」結構,詳細闡述了「精確控制社群數量」(說明了 Girvan-Newman 的「迭代特性」,介紹了「使用 itertools.islice() 提取分割」,並給出了「範例:獲取 4 個社群」),接著探討了「團體 (Cliques) 的識別與分析」(定義了「團體」,闡述了其「意義」,並介紹了「NetworkX 函數」),並說明了「最大團體 (Maximal Clique) 的識別與視覺化」(定義了「最大團體」,介紹了「查找方法」,並說明了「視覺化」方式),最後以「總結與展望」作結,強調了「Girvan-Newman 的靈活性」和「團體分析的價值」,並指出其「為後續網路結構分析奠定基礎」。