美國航空交通網路分析涉及大量的機場和航線資料,若直接視覺化呈現,容易形成難以解讀的「毛球圖」。為瞭解決這個問題,我們使用 Python 和 NetworkX 函式庫,結合機場的經緯度資訊,將網路節點定位在地理空間上,使視覺化更具地理意義。同時,根據航線流量調整邊的透明度,直觀地呈現不同航線的繁忙程度。為了深入分析航線流量的模式,我們引入了重力模型,該模型考量了機場吞吐量和距離對航線流量的影響,並計算每條航線的殘差,構建殘差網路以識別關鍵的機場連線。此外,本文也探討了動態網路分析方法,演示如何利用時間戳記資料建立網路快照,進而觀察網路結構的演變。
美國航空交通網路分析:從隨機佈局到地理空間佈局
在分析複雜網路時,適當的視覺化至關重要。以美國航空交通網路為例,本文將展示如何從一個雜亂無章的「毛球圖」轉變為具有地理意義的網路視覺化。
資料清理與初步視覺化
首先,從原始資料中移除不符合條件的機場節點,例如經緯度為零或超出合理範圍的機場。接著,利用NetworkX函式庫建立航空交通網路圖G_air,並移除斷開連線的機場。
import networkx as nx
import math
# 移除不符合條件的節點
for v in list(G_air.nodes):
try:
long = G_air.nodes[v]['long']
lat = G_air.nodes[v]['lat']
if long == 0 or long < -128.6 or lat == 0 or lat < 23.5:
G_air.remove_node(v)
continue
G_air.nodes[v]['lat'] = lat
G_air.nodes[v]['long'] = long
except KeyError:
G_air.remove_node(v)
# 保留最大連通元件
G_air = nx.subgraph(G_air, max(nx.connected_components(G_air), key=len))
# 初步視覺化(產生「毛球圖」)
nx.draw_networkx(G_air, node_size=0, with_labels=False, edge_color='#666666', alpha=0.1)
內容解密:
- 上述程式碼首先遍歷所有節點,檢查其經緯度是否合理,不合理的節點將被移除。
- 使用
nx.subgraph保留最大的連通元件,以去除孤立的機場。 - 初步視覺化由於缺乏有意義的佈局資訊,產生了難以解讀的「毛球圖」。
地理空間佈局的視覺化
為了提升視覺化的可讀性,利用機場的地理位置(經緯度)資訊建立節點的位置字典pos。
# 建立地理空間佈局的位置字典
pos = dict()
for v in G_air.nodes:
long = G_air.nodes[v]['long']
lat = G_air.nodes[v]['lat']
pos[v] = ((long + 90) * math.cos(2 * math.pi * lat / 360), lat)
# 使用地理空間佈局進行視覺化
fig = plt.figure(figsize=(15,15))
ax = plt.subplot(1, 1, 1)
max_weight = max([G_air.edges[e]['count'] for e in G_air.edges])
nx.draw_networkx_nodes(G_air, pos=pos, node_color='#7f7fff', node_size=20)
for e in G_air.edges:
alpha = G_air.edges[e]['count'] / max_weight
nx.draw_networkx_edges(G_air, pos=pos, edgelist=[e], edge_color='#7f7fff', alpha=alpha, arrows=False)
ax.set_aspect(1)
內容解密:
- 經過地理空間佈局轉換後,節點的位置更具實際意義,有助於理解航空交通網路的地理分佈特性。
- 每條邊的透明度(alpha值)與其流量成正比,直觀展示了不同航線的繁忙程度。
重力模型分析
為了進一步分析航線流量與距離、機場吞吐量之間的關係,引入重力模型。該模型假設兩機場間的流量與它們的吞吐量成正比,而與距離的平方成反比。
# 計算兩點間距離的Haversine公式實作
def haversine(q, p):
R_km = 6371
theta1 = q[1] * math.pi / 180
phi1 = q[0] * math.pi / 180
theta2 = p[1] * math.pi / 180
phi2 = p[0] * math.pi / 180
dphi = phi2 - phi1
dtheta = theta2 - theta1
a = (math.sin(dphi/2) * math.sin(dphi/2) + (math.cos(phi1) * math.cos(phi2) * math.sin(dtheta/2) * math.sin(dtheta/2)))
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = R_km * c
return d
# 為每條邊新增距離屬性
for v, w in G_air.edges:
p_v = (G_air.nodes[v]['lat'], G_air.nodes[v]['long'])
p_w = (G_air.nodes[w]['lat'], G_air.nodes[w]['long'])
G_air.edges[v, w]['distance'] = haversine(p_v, p_w)
# 計算每個機場的加權度(吞吐量)
degree = G_air.degree(weight='count')
nx.set_node_attributes(G_air, dict(degree), 'degree')
內容解密:
- Haversine公式用於計算地球上兩點間的大圓距離,考慮了地球的球面特性。
- 每個機場的加權度代表其總吞吐量,用於重力模型的計算。
動態網路分析:從空間到時間的轉變
在探討網路科學的過程中,我們不僅關注網路的靜態結構,還需要了解網路如何隨著時間變化。動態網路(Dynamic Networks)是研究網路隨時間演變的重要工具。本章將探討動態網路的基本概念、分析方法及其在真實世界中的應用。
殘差網路的建構與分析
在分析美國航空交通網路時,我們首先計算了每條航線的殘差,以評估其實際流量與預期流量之間的差異。殘差網路是由那些超出預期流量的航線組成,代表了最重要的機場連線。
程式碼實作:計算殘差並構建殘差網路
for v, w in G_air.edges:
if v == w:
continue
count = G_air.edges[v, w]['count']
# 計算預期權重
expected = (
g * G_air.nodes[v]['degree']
* G_air.nodes[w]['degree']
/ G_air.edges[v, w]['distance']**2)
G_air.edges[v, w]['expected'] = expected
# 計算殘差
G_air.edges[v, w]['residual'] = count - expected
G_air.edges[v, w]['log_residual'] = math.log10(count) - math.log10(expected)
# 篩選出殘差大於0的邊
residual_edges = [e for e in G_air.edges if G_air.edges[e]['log_residual'] > 0]
G_residual = G_air.edge_subgraph(residual_edges)
# 保留最大的連通元件
G_residual = nx.subgraph(G_residual, max(nx.connected_components(G_residual), key=len))
內容解密:
- 迴圈遍歷所有邊: 程式碼首先遍歷航空交通網路
G_air中的所有邊,跳過自環(self-loop)。 - 計算預期流量: 根據給定的公式計算每條邊的預期流量,考慮了節點的度數和距離的影響。
- 計算殘差: 比較實際流量與預期流量,計算殘差及其對數值。
- 構建殘差網路: 篩選出殘差對數值大於0的邊,構建殘差網路
G_residual。 - 保留最大連通元件: 對殘差網路進行處理,保留最大的連通元件,以聚焦於最重要的連線。
殘差網路的視覺化
透過視覺化殘差網路,我們可以更直覺地理解重要的機場連線。殘差網路相比原始的地理視覺化更加稀疏,更容易識別出關鍵節點和連線。
程式碼實作:殘差網路視覺化
fig = plt.figure(figsize=(15,15))
ax = plt.subplot(1, 1, 1)
max_weight = max([G_residual.edges[e]['log_residual'] for e in G_residual.edges])
nx.draw_networkx_nodes(G_residual, pos=pos, node_color='#7f7fff', node_size=20)
for e in G_residual.edges:
alpha = G_residual.edges[e]['log_residual'] / max_weight
nx.draw_networkx_edges(G_residual, pos=pos, edgelist=[e], edge_color='#7f7fff', alpha=alpha, arrows=False)
ax.set_aspect(1)
圖表翻譯:
此圖展示了美國航空交通的殘差網路,突出了最重要的機場連線。節點代表機場,邊代表超出預期流量的航線。邊的透明度(alpha值)與殘差對數值成正比,顯示了不同航線的重要程度。
網路屬性分析
透過比較原始航空交通網路和殘差網路的平均聚類別係數,我們發現原始網路具有很高的聚類別係數,而殘差網路的聚類別係數則明顯降低。
動態網路與時間分析
動態網路研究的是網路如何隨著時間變化。透過對網路在不同時間點的快照(snapshot)進行分析,可以瞭解網路屬性的演變。
程式碼實作:載入並分析維基百科連結資料
G_wiki = nx.read_edgelist(data_dir / 'ligtenberg2017' / 'wikilinks.csv', data=[('begin', int), ('end', int)], create_using=nx.MultiGraph)
len(G_wiki)
內容解密:
- 載入資料: 使用
read_edgelist函式從CSV檔案中載入維基百科連結資料,並指定開始和結束時間。 - 使用MultiGraph: 由於資料集中可能存在多重邊,使用
MultiGraph來儲存資料。 - 時間戳記: 時間以Unix時間戳記(自1970年1月1日以來的秒數)表示,便於比較。
快照分析與視覺化
透過定義函式 get_snapshot,我們可以在特定時間點生成網路快照,並對其進行視覺化,以觀察網路隨時間的變化。
程式碼實作:生成特定日期的網路快照
def get_snapshot(G, date):
dt = datetime.datetime.strptime(date, '%Y-%m-%d')
timestamp = time.mktime(dt.timetuple())
snapshot_edges = [e for e in G.edges if G.edges[e]['begin'] <= timestamp and G.edges[e]['end'] >= timestamp]
return nx.Graph(G.edge_subgraph(snapshot_edges))
內容解密:
- 日期轉換: 將日期字串轉換為Unix時間戳記。
- 篩選邊: 根據給定時間戳記篩選出存在的邊。
- 生成快照: 使用
edge_subgraph方法生成特定時間點的網路快照。
網路視覺化的進階技巧
網路視覺化是傳達關係和連線資訊最強大的工具之一。許多網路中龐大的資訊量使得建立清晰的視覺化變得棘手,有時會導致混亂的「毛球」現象。NetworkX能夠生成多種視覺化型別,遠遠超出了本文目前所見的範疇。本章涵蓋了一些更進階的視覺化技巧,包括額外的佈局和聚焦網路中最重要部分的方法。
超越毛球:瞭解什麼是好的視覺化
幾乎任何網路分析都會包含視覺化。有時,它們甚至是有幫助的。視覺化網路是很困難的。它們通常包含的資訊超過一頁紙所能容納的範圍,而高度連線的網路會導致許多邊緣相互交叉。太多次數的結果是一個「毛球」,這是人們對一個具有太多密集連線的網路視覺化的親切稱呼,以至於無法傳達任何有意義的資訊。建立一個清晰且有意義的網路視覺化需要了解可用的技術並知道何時應用它們。
環形佈局:小型網路的視覺化方法
環形佈局是一種簡單的方法,用於視覺化較小的網路。這種方法將節點均勻地分佈在一個圓圈上,能夠清晰地展示節點之間的連線關係。
import matplotlib.pyplot as plt
import networkx as nx
# 建立一個簡單的網路
G = nx.cycle_graph(10)
# 使用環形佈局進行視覺化
pos = nx.circular_layout(G)
nx.draw_networkx(G, pos, with_labels=True)
plt.title("環形佈局範例")
plt.show()
內容解密:
- 這段程式碼首先匯入必要的函式庫:
matplotlib.pyplot用於繪圖,networkx用於網路操作。 - 建立一個包含10個節點的環形網路。
- 使用
nx.circular_layout(G)計算節點的位置,使其均勻分佈在一個圓圈上。 - 使用
nx.draw_networkx(G, pos, with_labels=True)繪製網路,並顯示節點標籤。 - 最後,使用
plt.show()顯示圖表。
殼佈局:用於視覺化中心性的技術
殼佈局是一種技術,用於根據節點的重要性或中心性對其進行視覺化。這種方法透過將節點分層排列,能夠突出顯示最重要的節點。
import matplotlib.pyplot as plt
import networkx as nx
# 建立一個星形網路
G = nx.star_graph(10)
# 使用殼佈局進行視覺化
pos = nx.shell_layout(G)
nx.draw_networkx(G, pos, with_labels=True)
plt.title("殼佈局範例")
plt.show()
內容解密:
- 這段程式碼建立了一個星形網路,其中一個中心節點與其他10個節點相連。
- 使用
nx.shell_layout(G)計算節點的位置,將中心節點放在內層,其他節點放在外層。 - 使用
nx.draw_networkx(G, pos, with_labels=True)繪製網路,並顯示節點標籤。 - 最後,使用
plt.show()顯示圖表。
力導向佈局:用於視覺化社群結構的方法
力導向佈局是一種流行的用於視覺化社群結構的方法。這種方法透過模擬節點之間的力來排列節點,能夠清晰地展示社群之間的關係。
import matplotlib.pyplot as plt
import networkx as nx
# 建立一個隨機圖
G = nx.gnm_random_graph(20, 30)
# 使用力導向佈局進行視覺化
pos = nx.spring_layout(G)
nx.draw_networkx(G, pos, with_labels=True)
plt.title("力導向佈局範例")
plt.show()
內容解密:
- 這段程式碼建立了一個包含20個節點和30條邊的隨機圖。
- 使用
nx.spring_layout(G)計算節點的位置,透過模擬節點之間的力來排列節點。 - 使用
nx.draw_networkx(G, pos, with_labels=True)繪製網路,並顯示節點標籤。 - 最後,使用
plt.show()顯示圖表。
本章介紹了多種進階的網路視覺化技巧,包括環形佈局、殼佈局和力導向佈局等。這些方法能夠幫助我們更好地理解和分析複雜的網路結構。下一章將繼續探討更多關於網路分析的高階主題。