代理人模擬是一種用於研究複雜系統的技術,它模擬多個互動的代理人,這些代理人的狀態會隨著時間推移而改變。本文使用代理人模擬技術研究社會學習過程,其中代理人透過與鄰居互動來更新他們對某個量的信念。我們使用 Python 和 NetworkX 函式庫建立了不同拓撲結構的網路,包括空手道俱樂部網路、組態模型網路、優先連線網路、環狀網路和 Watts-Strogatz 網路,並模擬了在這些網路中代理人的信念如何隨著時間推移而收斂。
社會學習的代理人模擬:網路結構對信念收斂的影響
在複雜系統的研究中,代理人模擬(Agent-based modeling)是一種常見的技術,用於模擬多個稱為代理人的物件。每個代理人由其狀態描述,狀態可以是一個簡單的數字或複雜的資料結構。隨著模擬的進行,每個代理人與其他代理人互動,並根據這些互動更新其狀態。在網路環境中,代理人是網路中的節點,只能與其鄰居互動。
社會學習過程的模擬
社會學習是指個體透過與他人溝通來改進對某個量的估計的過程。一個簡單的方法是每個代理人平均其鄰居的估計,並將該平均值用作其新的估計。以下函式生成初始的代理人信念:
def initial_beliefs(G, true_value=0, std=15):
"""生成具有常態分佈誤差的真實值的估計。"""
beliefs = dict((v, random.gauss(true_value, std)) for v in G.nodes())
return beliefs
內容解密:
- 函式
initial_beliefs接受一個圖G、真實值true_value和標準差std作為輸入。 - 使用常態分佈隨機數生成每個節點的初始信念。
- 傳回一個字典,其中鍵是節點,值是對應的初始信念。
我們可以使用上述函式生成初始信念,並透過多次呼叫 learning_step 函式來模擬社會學習過程:
def learning_step(G, beliefs):
"""根據鄰居的信念更新每個節點的信念。"""
new_beliefs = dict()
for v in G.nodes():
total = beliefs[v]
count = 1
for w in G.neighbors(v):
total += beliefs[w]
count += 1
new_beliefs[v] = total / count
return new_beliefs
內容解密:
- 函式
learning_step接受一個圖G和當前信念beliefs作為輸入。 - 對每個節點,計算其鄰居信念的平均值,並將該平均值作為新的信念。
- 傳回一個字典,其中包含更新後的信念。
不同網路拓撲下的社會學習
不同網路結構對社會學習過程中的信念收斂有著不同的影響。以下程式碼模擬了不同網路下的社會學習過程:
networks = {
'Karate Club': G_karate,
'Configuration Model': G_configuration,
'Preferential Attachment': nx.barabasi_albert_graph(34, 1),
'Ring': nx.watts_strogatz_graph(34, 6, 0),
'Watts-Strogatz (p=0.3)': nx.watts_strogatz_graph(34, 6, 0.1),
'Watts-Strogatz (p=1)': nx.watts_strogatz_graph(34, 6, 1)
}
for i, (title, G) in enumerate(networks.items()):
plt.subplot(3, 2, i + 1)
plt.title(title)
plot_beliefs(G, beliefs, 42)
plt.tight_layout()
內容解密:
- 定義了一個包含不同網路結構的字典
networks。 - 對每個網路,使用
plot_beliefs函式繪製信念隨時間變化的圖表。 - 使用
plt.subplot和plt.tight_layout將多個圖表排列在一起。
結果分析
所有模擬結果都趨向於真實值(42),但收斂的細節在不同網路結構之間差異很大。結果表明,網路結構對社會學習過程中的信念收斂有著重要的影響。
網路在空間與時間中的應用
在前面的章節中,我們探討了網路的基本概念和特性,但大多數情況下,節點(nodes)並未與特定的時間或空間相關聯。實際上,許多重要的網路都與特定的地理位置或時間相關,例如電網、道路網路、機場之間的航線等。本章將介紹一些特殊的技術,用於分析和視覺化這些與空間和時間相關的網路。
空間中的網路
許多重要的網路都與特定的地理位置相關,例如:
- 電網
- 道路網路
- 機場之間的直飛航線
- 電信線路
這些網路中的邊(edges)是物理物件,具有物理屬性,這些屬性會影響由網路所代表的系統的行為。單一的權重衡量並不總是足夠的。例如,當一條邊代表一條光纖電信纜時,纜線的物理長度和頻寬(容量)都是重要的考量因素。前者影響訊號沿著纜線傳輸的時間,而後者則影響它可以處理的資料量。
重力模型
在空間網路中,長度通常與成本相關,無論是鋪設纜線的貨幣成本,還是長途飛行的時間成本。因此,這些網路往往由許多短邊和較少的長邊構成。同樣地,一些型別的網路表現出邊權重隨著邊的長度而減少的特性。例如,在兩個機場之間直接旅行的乘客數量通常隨著距離的增加而減少。因此,如果一條邊具有高權重,可能只是因為它很短,也可能是因為有一些更有趣的事情正在發生。可以使用稱為重力模型的技術來糾正長度對邊權重的影響。
重力模型假設,平均而言,兩個點之間的互動作用強度與它們之間的距離平方成反比。它們被稱為重力模型,是因為在物理學中,兩個物體之間的引力遵循類別似的定律(至少在你進入研究生院之前)。互動作用的強度也被假設為與每個節點的一些類別似品質的屬性成正比,例如透過機場的總流量。
空間資料分析例項
本文將提供在NetworkX中處理空間資料的示例。特別是,這些示例分析了2018年美國大陸的直飛航班。在這個網路中,節點代表機場,邊代表這些機場之間的乘客流量。這是一個空間網路,因為機場對應於地理位置,每條邊所跨越的距離在分析網路時是相關的。
# 將資料檔案載入到網路中
from pathlib import Path
import networkx as nx
data_dir = Path('.') / 'data'
G_air = nx.Graph()
with open(data_dir / 'BTS2018' / 'carrier.csv') as f:
# 跳過標頭
next(f)
# 迴圈遍歷資料行
for row in f:
count, v, w, year, month = row.strip().split(',')
count = int(count)
if count == 0 or v == w:
continue
try:
G_air.edges[v, w]['count'] += count
except KeyError:
G_air.add_edge(v, w, count=count)
載入機場的地理位置資訊
我們可以使用機場程式碼將每個機場與全球機場資料函式庫(Partow, 2019)中的緯度和經度進行匹配。首先,將緯度和經度載入到一個字典中:
airport_lat_long = {}
with open(data_dir / 'partow' / 'GlobalAirportDatabase.txt') as f:
for row in f:
columns = row.strip().split(':')
code = columns[1]
lat = float(columns[14])
long = float(columns[15])
airport_lat_long[code] = (lat, long)
然後,在這個字典中查詢每個節點,丟棄不在美國大陸的節點:
for v in list(G_air.nodes()):
try:
lat, long = airport_lat_long[v]
# 進一步處理...
except KeyError:
# 處理未找到機場程式碼的情況
continue
內容解密:
data_dir = Path('.') / 'data':這行程式碼設定了資料檔案的路徑。Path('.')表示當前目錄,/'data'則是子目錄。G_air = nx.Graph():建立了一個新的空圖(Graph),用於儲存機場之間的連線。with open(data_dir / 'BTS2018' / 'carrier.csv') as f::開啟包含航班資料的CSV檔案。next(f):跳過CSV檔案的標題行。- 迴圈遍歷資料行:對於每一行資料,提取乘客數量、起飛和降落機場程式碼等資訊,並更新圖中的邊權重。
airport_lat_long字典:儲存機場程式碼到其緯度和經度的對映。- 節點查詢和過濾:遍歷圖中的每個節點,利用機場程式碼查詢其緯度和經度,並根據需要過濾掉不在美國大陸的機場。
這個例子展示瞭如何使用NetworkX處理和分析空間網路資料,包括載入資料、構建網路、以及如何利用額外的地理資訊對網路進行分析。### 網路在時間中的應用
除了空間中的網路外,許多網路還會隨著時間變化。在本章中,我們還將探討如何視覺化和分析這些隨著時間變化的網路。
時間中的網路
在許多情況下,網路中的關係會隨著時間而改變。例如:
- 社交網路中的朋友關係可能會隨著時間而變化
- 網站之間的超連結可能會被建立或刪除
- 公司的組織結構可能會隨著時間而調整
分析時間中的網路
分析時間中的網路需要特殊的技術。我們可以使用動態網路(dynamic networks)或時間網路(temporal networks)來表示這些隨著時間變化的關係。
結合空間和時間的分析
當網路同時具有空間和時間特性時,我們需要結合上述技術來進行分析和視覺化。例如,在分析航空網路時,我們不僅需要考慮機場之間的地理距離,還需要考慮航班時刻表和乘客流量的變化。
例項:分析航空網路的時間特性
# 假設我們已經有了 G_air 網路,並且已經載入了機場的地理位置資訊
# 分析航空網路的時間特性,例如每月或每季度的乘客流量變化
import pandas as pd
# 載入包含時間資訊的資料
data = pd.read_csv(data_dir / 'BTS2018' / 'carrier.csv')
# 將資料按照時間(例如月份)進行分組,並計算每組的乘客總數
data['time'] = pd.to_datetime(data[['year', 'month']].assign(DAY=1))
data_grouped = data.groupby(pd.Grouper(key='time', freq='M'))['count'].sum().reset_index()
# 使用結果進行進一步的分析和視覺化
內容解密:
data = pd.read_csv(data_dir / 'BTS2018' / 'carrier.csv'):使用 pandas 載入包含航班資料的 CSV 檔案。data['time'] = pd.to_datetime(data[['year', 'month']].assign(DAY=1)):將年份和月份資訊轉換為 datetime 物件,以便進行時間序列分析。data_grouped = data.groupby(pd.Grouper(key='time', freq='M'))['count'].sum().reset_index():按照月份對資料進行分組,並計算每月的乘客總數。
透過這種方式,我們可以深入瞭解航空網路在時間維度上的變化特性,並結合空間特性進行綜合分析。
美國航空交通網路分析:從地理空間佈局到重力模型
在分析複雜網路時,理解節點和邊的空間分佈對於深入洞察網路特性至關重要。本文以美國航空交通網路為例,展示如何利用地理空間資訊最佳化網路視覺化,並應用重力模型分析航空交通流量。
網路資料清理與初步視覺化
首先,我們從開放航班資料函式庫中構建美國航空交通網路 G_air。資料清理過程中,移除經緯度異常或為零的機場節點,以確保網路資料的準確性。
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))
內容解密:
- 移除異常節點:檢查每個機場節點的經緯度,若經度為0或超出合理範圍(例如小於-128.6),或緯度為0或小於23.5,則移除該節點。
- 保留最大連通分量:使用
nx.subgraph和max(nx.connected_components(G_air), key=len)確保網路僅包含最大的連通子圖,避免孤立節點幹擾分析。
初步使用 nx.draw_networkx 繪製網路時,由於節點和邊過多,形成難以解讀的「毛球圖」。
地理空間佈局最佳化視覺化
為了提升視覺化效果,我們根據機場的地理位置(經緯度)手動建立節點位置字典 pos,並將其應用於網路繪製。
import math
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)
內容解密:
- 地理座標轉換:將經緯度轉換為平面座標,考慮了緯度對經度縮放的影響,使地圖投影更準確。
- 邊透明度調整:根據航班流量調整邊的透明度,直觀展示不同航線的繁忙程度。
重力模型分析航空交通流量
重力模型用於分析兩個機場之間的交通流量是否符合預期,考慮距離和端點「品質」(此處為機場的總流量)的影響。
計算距離與節點品質
首先,使用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)
內容解密:
- Haversine公式:用於計算球面上兩點之間的距離,假設地球為理想球體。
- 距離屬性指定:將計算出的距離賦予每條邊的
distance屬性。
接著,計算每個機場的總流量(加權度),並將其作為節點的「品質」。
degree = G_air.degree(weight='count')
nx.set_node_attributes(G_air, dict(degree), 'degree')
內容解密:
- 加權度計算:計算每個機場的總流量,作為其在重力模型中的「品質」。
殘差分析與模型評估
透過比較預期流量與實際流量,計算殘差,以判斷航線是否具有特殊性(如因經濟或旅遊因素導致的異常流量)。
g_list = []
for v, w in G_air.edges():
if v >= w:
continue
try:
count = G_air.edges[v, w]['count']
except KeyError:
g_list.append(0)
continue
distance = G_air.edges[v, w]['distance']
v_degree = G_air.nodes[v]['degree']
w_degree = G_air.nodes[w]['degree']
g_list.append(count * distance**2 / v_degree / w_degree)
g = 10**(sum([math.log10(g) for g in g_list]) / len(g_list))
內容解密:
- 殘差計算:透過比較實際流量與根據重力模型的預期流量,分析航線的特殊性。
- 幾何平均數:用於計算重力模型中的常數乘數
g,適合處理重尾分佈資料。