用 NetworkX + Gephi + Nebula Graph 分析<權力的遊戲>人物關係(下)
在上一篇[1]中,我們透過 NetworkX 和 Gephi 展示了<權力的遊戲>中的人物關係。在本篇中,我們將展示如何透過 NetworkX 訪問圖資料庫 Nebula Graph。
NetworkX
NetworkX [2] 是一個用 Python 語言開發的圖論與複雜網路建模工具,內建了大量常用的圖與複雜網路分析演算法,可以方便地進行復雜網路資料分析、模擬建模等工作,功能豐富,簡單易用。
在 NetworkX 中,圖是由頂點、邊和可選的屬性構成的資料結構。頂點表示資料,邊是由兩個頂點唯一確定的,表示兩個頂點之間的關係。頂點和邊也可以擁有更多的屬性,以儲存更多的資訊。
NetworkX 支援 4 種類型的圖:
Graph:無向圖
DiGraph: 有向圖
MultiGraph: 多重無向圖
MultiDiGraph: 多重有向圖
在 NetworkX 中建立一個無向圖:
import
networkx
as
nx
G
=
nx
。
Graph
()
新增頂點:
G
。
add_node
(
1
)
G
。
add_nodes_from
([
2
,
3
,
4
])
G
。
add_node
(
2
,
name
=
‘Tom’
,
age
=
23
)
新增邊:
G
。
add_edge
(
2
,
3
)
G
。
add_edges_from
([(
1
,
2
),(
1
,
3
)])
g
。
add_edge
(
1
,
2
,
start_year
=
1996
,
end_year
=
2019
)
在上一篇文章(一)中,我們已經演示了 NetworkX 的 Girvan-Newman 社群發現演算法。
圖資料庫 Nebula Graph
NetworkX 通常使用本地檔案作為資料來源,這在靜態網路研究的時候沒什麼問題,但如果圖網路經常會發生變化——例如某些中心節點已經不存在(Fig。1)或者引入了重要的網路拓撲變化(Fig。2)——每次生成全新的靜態檔案再載入分析就有些麻煩,最好整個變化過程可以持久化在一個數據庫中,並且可以實時地直接從資料庫中載入子圖或者全圖做分析。本文選用 Nebula Graph [3]作為儲存圖資料的圖資料庫。
Fig。 1
Fig。 2
Nebula Graph 提供了兩種方式來獲取圖結構:
編寫一個查詢語句,拉取一個子圖;
全量掃描底層儲存,獲取一個完整的全圖。
第一種方式適合在一個大規模的圖網路中透過精細的過濾和剪枝條件來獲取符合需求的若干個點和邊。第二種方式更適合於全圖的分析,這通常是在專案前期對全圖進行一些啟發式探索,當有進一步認知後再用第一種方式做精細的剪枝分析。
分析完 Nebula Graph 兩種獲取圖結構方式後,下面來檢視 Nebula Graph 的 Python 客戶端程式碼,nebula-python/nebula/ngStorage/StorageClient。py 與 nebula-python/nebula/ngMeta/MetaClient。py 就是和底層儲存互動的 API, 裡面有掃描點、掃描邊、讀取一堆屬性等等一系列豐富的介面。
下面兩個介面可以用來讀取所有的點、邊資料:
def
scan_vertex
(
self
,
space
,
return_cols
,
all_cols
,
limit
,
start_time
,
end_time
)
def
scan_edge
(
self
,
space
,
return_cols
,
all_cols
,
limit
,
start_time
,
end_time
)
1) 初始化一個客戶端,和一個 scan_edge_processor。scan_edge_processor 用來對讀出來的邊資料進行解碼:
meta_client
=
MetaClient
([(
‘192。168。8。16’
,
45500
)])
meta_client
。
connect
()
storage_client
=
StorageClient
(
meta_client
)
scan_edge_processor
=
ScanEdgeProcessor
(
meta_client
)
2) 初始化 scan_edge 介面的各項引數:
space_name
=
‘nba’
# 要讀取的圖空間名稱
return_cols
=
{}
# 要返回的邊(或點)及其屬性列
return_cols
[
‘serve’
]
=
[
‘start_year’
,
‘end_year’
]
return_cols
[
‘follow’
]
=
[
‘degree’
]
allCols
=
False
# 是否返回所有屬性列,當該值為 False 時,僅返回在 returnCols 裡指定的屬性列,當為 True 時,返回所有屬性列
limit
=
100
# 最多返回的資料條數
start_time
=
0
end_time
=
sys
。
maxsize
3) 呼叫 scan_part_edge 介面,該介面會返回一個 scan_edge_response 物件的迭代器:
scan_edge_response_iterator
=
storage_client
。
scan_edge
(
space_name
,
return_cols
,
all_cols
,
limit
,
start_time
,
end_time
)
4) 不斷讀取該迭代器所指向的 scan_edge_response 物件中的資料,直到讀取完所有資料:
while
scan_edge_response_iterator
。
has_next
():
scan_edge_response
=
scan_edge_response_iterator
。
next
()
if
scan_edge_response
is
None
:
(
“Error occurs while scaning edge”
)
break
process_edge
(
space
,
scan_edge_response
)
其中,process_edge 是自定義的一個處理讀出來邊資料的函式,該函式可以先使用 scan_edge_processor 對 scan_edge_response 中的資料進行解碼,解碼後的資料可以直接打印出來,也可以做一些簡單處理,另作他用,比如:將這些資料讀入計算框架 NetworkX 裡。
5) 處理資料。在這裡我們將讀出來的所有邊都新增到 NetworkX 中的圖G 裡:
def
process_edge
(
space
,
scan_edge_response
):
result
=
scan_edge_processor
。
process
(
space
,
scan_edge_response
)
# Get the corresponding rows by edge_name
for
edge_name
,
edge_rows
in
result
。
rows
。
items
():
for
row
in
edge_rows
:
srcId
=
row
。
default_properties
[
0
]
。
get_value
()
dstId
=
row
。
default_properties
[
2
]
。
get_value
()
(
‘
%d
->
%d
’
%
(
srcId
,
dstId
))
props
=
{}
for
prop
in
row
。
properties
:
prop_name
=
prop
。
get_name
()
prop_value
=
prop
。
get_value
()
props
[
prop_name
]
=
prop_value
G
。
add_edges_from
([(
srcId
,
dstId
,
props
)])
# 新增邊到 NetworkX 中的圖G
讀取頂點資料的方法和上面的流程類似。
此外,對於分散式的一些圖計算框架[4]來說,Nebula Graph 還提供了根據分片 (partition) 併發地批次讀取儲存的功能,這會在之後的文章中演示。
在 NetworkX 中進行圖分析
當我們把所有點和邊資料都按照上述流程讀入 NetworkX 後,我們還可以做一些基本的圖分析和圖計算:
1) 繪製圖:
nx
。
draw
(
G
,
with_labels
=
True
,
font_weight
=
‘bold’
)
import
matplotlib。pyplot
as
plt
plt
。
show
()
plt
。
savefig
(
‘。/test。png’
)
繪製出來的圖:
2) 打印出圖中的所有點和邊:
(
‘nodes: ’
,
list
(
G
。
nodes
))
(
‘edges: ’
,
list
(
G
。
edges
))
輸出的結果:
nodes
:
[
109
,
119
,
129
,
139
,
149
,
209
,
219
,
229
,
108
,
118
,
128
,
138
,
148
,
208
,
218
,
228
,
107
,
117
,
127
,
137
,
147
,
207
,
217
,
227
,
106
,
116
,
126
,
136
,
146
,
206
,
216
,
226
,
101
,
111
,
121
,
131
,
141
,
201
,
211
,
221
,
100
,
110
,
120
,
130
,
140
,
150
,
200
,
210
,
220
,
102
,
112
,
122
,
132
,
142
,
202
,
212
,
222
,
103
,
113
,
123
,
133
,
143
,
203
,
213
,
223
,
104
,
114
,
124
,
134
,
144
,
204
,
214
,
224
,
105
,
115
,
125
,
135
,
145
,
205
,
215
,
225
]
edges
:
[(
109
,
100
),
(
109
,
125
),
(
109
,
204
),
(
109
,
219
),
(
109
,
222
),
(
119
,
200
),
(
119
,
205
),
(
119
,
113
),
(
129
,
116
),
(
129
,
121
),
(
129
,
128
),
(
129
,
216
),
(
129
,
221
),
(
129
,
229
),
(
129
,
137
),
(
139
,
138
),
(
139
,
212
),
(
139
,
218
),
(
149
,
130
),
(
149
,
219
),
(
209
,
123
),
(
219
,
130
),
(
219
,
112
),
(
219
,
104
),
(
229
,
147
),
(
229
,
116
),
(
229
,
141
),
(
229
,
144
),
(
108
,
100
),
(
108
,
101
),
(
108
,
204
),
(
108
,
206
),
(
108
,
214
),
(
108
,
215
),
(
108
,
222
),
(
118
,
120
),
(
118
,
131
),
(
118
,
205
),
(
118
,
113
),
(
128
,
116
),
(
128
,
121
),
(
128
,
201
),
(
128
,
202
),
(
128
,
205
),
(
128
,
223
),
(
138
,
115
),
(
138
,
204
),
(
138
,
210
),
(
138
,
212
),
(
138
,
221
),
(
138
,
225
),
(
148
,
127
),
(
148
,
136
),
(
148
,
137
),
(
148
,
214
),
(
148
,
223
),
(
148
,
227
),
(
148
,
213
),
(
208
,
127
),
(
208
,
103
),
(
208
,
104
),
(
208
,
124
),
(
218
,
127
),
(
218
,
110
),
(
218
,
103
),
(
218
,
104
),
(
218
,
114
),
(
218
,
105
),
(
228
,
146
),
(
228
,
145
),
(
107
,
100
),
(
107
,
204
),
(
107
,
217
),
(
107
,
224
),
(
117
,
200
),
(
117
,
136
),
(
117
,
142
),
(
127
,
114
),
(
127
,
212
),
(
127
,
213
),
(
127
,
214
),
(
127
,
222
),
(
127
,
226
),
(
127
,
227
),
(
137
,
136
),
(
137
,
213
),
(
137
,
150
),
(
147
,
136
),
(
147
,
214
),
(
147
,
223
),
(
207
,
121
),
(
207
,
140
),
(
207
,
122
),
(
207
,
134
),
(
217
,
126
),
(
217
,
141
),
(
217
,
124
),
(
217
,
144
),
(
106
,
204
),
(
106
,
212
),
(
106
,
113
),
(
116
,
141
),
(
116
,
126
),
(
116
,
210
),
(
116
,
216
),
(
116
,
121
),
(
116
,
113
),
(
116
,
105
),
(
126
,
216
),
(
136
,
210
),
(
136
,
213
),
(
136
,
214
),
(
146
,
202
),
(
146
,
210
),
(
146
,
215
),
(
146
,
222
),
(
146
,
226
),
(
206
,
123
),
(
216
,
144
),
(
216
,
105
),
(
226
,
140
),
(
226
,
112
),
(
226
,
114
),
(
226
,
144
),
(
101
,
100
),
(
101
,
102
),
(
101
,
125
),
(
101
,
204
),
(
101
,
215
),
(
101
,
113
),
(
101
,
104
),
(
111
,
200
),
(
111
,
204
),
(
111
,
215
),
(
111
,
220
),
(
121
,
202
),
(
121
,
215
),
(
121
,
113
),
(
121
,
134
),
(
131
,
205
),
(
131
,
220
),
(
141
,
124
),
(
141
,
205
),
(
141
,
225
),
(
201
,
145
),
(
211
,
124
),
(
221
,
104
),
(
221
,
124
),
(
100
,
125
),
(
100
,
204
),
(
100
,
102
),
(
100
,
113
),
(
100
,
104
),
(
100
,
144
),
(
100
,
105
),
(
110
,
204
),
(
110
,
220
),
(
120
,
150
),
(
120
,
202
),
(
120
,
205
),
(
120
,
113
),
(
140
,
114
),
(
140
,
214
),
(
140
,
224
),
(
150
,
143
),
(
150
,
213
),
(
200
,
142
),
(
200
,
104
),
(
200
,
145
),
(
210
,
124
),
(
210
,
144
),
(
210
,
115
),
(
210
,
145
),
(
102
,
203
),
(
102
,
204
),
(
102
,
103
),
(
102
,
135
),
(
112
,
204
),
(
122
,
213
),
(
122
,
223
),
(
132
,
225
),
(
202
,
133
),
(
202
,
114
),
(
212
,
103
),
(
222
,
104
),
(
103
,
204
),
(
103
,
114
),
(
113
,
104
),
(
113
,
105
),
(
113
,
125
),
(
113
,
204
),
(
133
,
114
),
(
133
,
144
),
(
143
,
213
),
(
143
,
223
),
(
203
,
135
),
(
213
,
124
),
(
213
,
145
),
(
104
,
105
),
(
104
,
204
),
(
104
,
215
),
(
114
,
115
),
(
114
,
204
),
(
134
,
224
),
(
144
,
145
),
(
144
,
214
),
(
204
,
105
),
(
204
,
125
)]
3) 常見的,可以計算兩個點之間的最短路徑:
p1
=
nx
。
shortest_path
(
G
,
source
=
114
,
target
=
211
)
(
‘頂點 114 到頂點 211 的最短路徑: ’
,
p1
)
輸出的結果:
頂點
114
到頂點
211
的最短路徑
:
[
114
,
127
,
208
,
124
,
211
]
4) 也計算圖中每個點的 PageRank 值,來看各自的影響力:
(
nx
。
pagerank
(
G
))
輸出的結果:
{109: 0。011507076520104863, 119: 0。007835838669313514, 129: 0。015304593799331218, 139: 0。007772926737873626, 149: 0。0073896601012629825, 209: 0。0065558926178649985, 219: 0。014100908598251508, 229: 0。011454115940170253, 108: 0。01645334474680034, 118: 0。01010598371500564, 128: 0。01594717876199238, 138: 0。01671097227127263, 148: 0。015898676579503977, 208: 0。009437234075904938, 218: 0。0153795416919104, 228: 0。005900393773635255, 107: 0。009745182763645681, 117: 0。008716335675518244, 127: 0。021565565312365507, 137: 0。011642680498867146, 147: 0。009721031073465738, 207: 0。01040504770909835, 217: 0。012054472529765329, 227: 0。005615576255373405, 106: 0。007371191843767635, 116: 0。020955704443679106, 126: 0。007589432032220849, 136: 0。015987209357117116, 146: 0。013922108926721374, 206: 0。008554794629575304, 216: 0。011219193251536395, 226: 0。013613173390725904, 101: 0。016680863106330837, 111: 0。010121524312495604, 121: 0。017545503989576015, 131: 0。008531567756846938, 141: 0。014598319866130227, 201: 0。0058643663430632525, 211: 0。003936285336338021, 221: 0。009587911774927793, 100: 0。02243017302167168, 110: 0。007928429795381916, 120: 0。011875669801396205, 130: 0。0073896601012629825, 140: 0。01205992633948699, 150: 0。010045605782606326, 200: 0。015289870550944322, 210: 0。017716629501785937, 220: 0。008666577509181518, 102: 0。014865431161046641, 112: 0。007931095811770324, 122: 0。008087439927630492, 132: 0。004659566123187912, 142: 0。006487446038191551, 202: 0。013579313206377282, 212: 0。01190888044566142, 222: 0。011376739416933006, 103: 0。013438110749144392, 113: 0。02458154500563397, 123: 0。01104978432213578, 133: 0。00743370900670294, 143: 0。008011123394996112, 203: 0。006883198710237787, 213: 0。020392557117890422, 223: 0。012345866520333572, 104: 0。024902235588979776, 114: 0。019369722463816744, 124: 0。017165705442951484, 134: 0。008284361176173354, 144: 0。019363506469972095, 204: 0。03507634139024834, 214: 0。015500649025348538, 224: 0。008320315540621754, 105: 0。01439975542831122, 115: 0。007592722237637133, 125: 0。010808523955754608, 135: 0。006883198710237788, 145: 0。014654713389044883, 205: 0。014660118545887803, 215: 0。01337467974572934, 225: 0。009909720748343093}
此外,也可以和上一篇中一樣,接入Gephi [5]來得到更好的圖視覺化效果。
本文的程式碼可以參見[6]。
Reference
[1]
https://
nebula-graph。com。cn/pos
ts/game-of-thrones-relationship-networkx-gephi-nebula-graph/
[2]
https://
networkx。github。io/
[3] https://github。com/vesoft-inc/nebula
[4]
https://
spark。apache。org/graphx
/
[5]
https://
gephi。org/
[6]
https://
github。com/vesoft-inc/n
ebula-python/pull/31
喜歡這篇文章?來來來,給我們的 GitHub 點個 star 表鼓勵啦~~ ♂️ ♀️ [手動跪謝]
交流圖資料庫技術?交個朋友,Nebula Graph 官方小助手微信:NebulaGraphbot 拉你進交流群~~
作者有話說:Hi,我是王傑,是圖資料 Nebula Graph 研發工程師,希望本次的經驗分享能給大家帶來幫助,如有不當之處也希望能幫忙糾正,謝謝~
上一篇:html相簿程式碼(1)
下一篇:甄嬛傳之華妃重生(二十)