NetworkX: communicability betweenness centrality
๐ ๋ชฉ์ฐจ (Contents)
Centrality - communicability betweenness centrality
- ์ ํต์ ์ธ ๊ฐ๋ ์์๋ network๋ฅผ ๋ถ์ํ ๋, shortest path๋ง์ ๊ณ ๋ คํ๊ฒ ๋ฉ๋๋ค. ํ์ง๋ง, ์ด๋ ์ค์ฌ์ ์ธ graph์ ํน์ฑ์ ๋ฐ์ํ์ง ๋ชปํ์ฃ . shortest path๊ฐ ์๋๋๋ผ๋, path๋ ์ฌ๋ฌ๊ฐ ์กด์ฌํ๋ฉฐ, non-shortest path๋ฅผ ํตํด์ ์ํฅ์ ๋ฐ๊ฒ ๋์ฃ .
- ๋ฐ๋ผ์, shortest path๋ง์ ๊ณ ๋ คํ ์ ํต์ ์ธ betweenness centrality๋ฅผ ๊ตฌํ๋ ๊ฒ์ด ์๋๋ผ, ์๋ก ๋ค๋ฅธ node pair ๊ฐ์ ์กด์ฌํ๋ ๋ชจ๋ path๋ฅผ ๊ณ ๋ คํด์, betweenness centrality๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด ํ์ํฉ๋๋ค.
- ๊ฐ๋ ์ ์ผ๋ก๋ ์ด๋ ต์ง ์์ต๋๋ค. ์ด์ ์๋ ๊ทธ์ โshortest pathโ์ ๋ํด์๋ง ํด๋น ๋ ธ๋๊ฐ ํฌํจ๋์๋์ง ํ์ธํ๋ค๋ฉด, ์ด์ ๋ ๋ ์ฌ์ด์ ๋ชจ๋ ๋ ธ๋ path์ ๋ํด์ ๊ฐ path ๋ณ๋ก ํด๋น ๋ ธ๋๊ฐ ํฌํจ๋๋์ง ํ์ธํ๋ฉด ๋ฉ๋๋ค. ๊ฐ๋จํ๊ฒ ์ฝ๋๋ก ์ฐ๋ฉด ๋ค์๊ณผ ๊ฐ์ฃ
r_dict = {r:0 for r in inputG}
for r in inputG:# ๋ชจ๋ r์ ๋ํด์
for p in inputG: # p์์ q๋ก ๊ฐ๋ ๋ชจ๋ path์ค์์
for q in inputG:
if (p!=q) and (q!=r):
# path_p_q_r / path_p_r
r_dict[r] += len(path_p_r_q) / len(path_p_q)
- ๋ฌผ๋ก , ์ง์ง ์ด๋ ๊ฒ ๊ณ์ฐํ๋ฉด ๊ณ์ฐ์ ๋ณต์ก๋๊ฐ ๋งค์ฐ ์ฆ๊ฐํฉ๋๋ค. ์ค์ ๋ก๋ matrix exponential์ผ๋ก ์ฒ๋ฆฌํ์ฌ ํฉํด์ฃผ๋ ์์ผ๋ก ์ฒ๋ฆฌ๋์ฃ . ์์ธํ ๋ด์ฉ์ networkx - communicability betweenness centrality์์ ๋ณด์๊ณ , ์์ ์ฝ๋๋ ๊ฐ๋ ์ ์ผ๋ก๋ง ์ดํดํ์๋ฉด ๋ฉ๋๋ค.
Do it using Networkx
- ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ๊ฐ๋จํ๊ฒ,
communcation betweenness centrality๋ฅผ ๊ณ์ฐํ๋ ํจ์๋ฅผ ๋ง๋ค๊ณ ,nx.communicability_betweenness_centrality(G)์ ๊ฐ์ ๋น๊ตํฉ๋๋ค. - ์๊ฐ๋ถํฐ, ๋งํ์๋ฉด, ๋น์ฐํ, loop๋ฅผ ๋ฐ๋ณตํ ๊ฒฝ์ฐ๊ฐ ํจ์ฌ ๋ง์ด ์์๋์ฃ .
import numpy as np
import networkx as nx
import time
# Graph generation
N = 10 # node size
p = 0.5
G = nx.fast_gnp_random_graph(N, p, seed=0)
print(nx.is_connected(G))
def custom_comm_bet_cent(inputG):
"""
- communicability betweenness centrality๋ shortest path๋ง ๊ณ ๋ คํ๋ ๊ฒ์ด ์๋๋ผ,
๋ชจ๋ ๋๋ฌ๊ฐ๋ฅํ ๋ชจ๋ path๋ฅผ ๊ณ ๋ คํฉ๋๋ค.
- matrix๋ก ํธ๋ ๋ฐฉ๋ฒ๋ ์์ผ๋, ์ฌ๊ธฐ์๋ ์ดํด๊ฐ ์ฝ๋๋ก ๋ค์๊ณผ ๊ฐ์ด, ์ผ์ผ์ด path๋ฅผ ํ์ธํ์ฌ ๊ฒ์ฐํฉ๋๋ค.
- ์ฆ, node `r`์ communicability bet cent๋
- ๋ชจ๋ node pair p๋ถํฐ q๊น์ง์ ๋ชจ๋ path์ค์์,
- r์ด ํฌํจ๋ path์ ๋น์จ์ ๋ชจ๋ ํฉํ์ฌ ๊ณ์ฐ๋๋ค.
"""
C = (len(inputG)-1)*(len(inputG)-2)
r_dict = {r:0 for r in inputG}
for r in inputG:# ๋ชจ๋ r์ ๋ํด์
for p in inputG: # p์์ q๋ก ๊ฐ๋ ๋ชจ๋ path์ค์์
for q in inputG:
if (p!=q) and (q!=r):
#print(f"== {p}, {q}")
path_p_q = list(nx.all_simple_paths(inputG, p, q))
path_p_q_r = filter(lambda x: True if r in x else False, path_p_q)
path_p_q_r = list(path_p_q_r)
r_dict[r] += len(path_p_q_r) / len(path_p_q)
# normalization
r_dict = {k: v/C for k, v in r_dict.items()}
#print(r_dict)
return r_dict
# Compute communicability betweenness centrality
custom_cbc_time = time.time()
custom_comm_bet_cent = custom_comm_bet_cent(G)
custom_cbc_time = time.time() - custom_cbc_time
nx_cbc_time = time.time()
nx_comm_bet_cent = nx.communicability_betweenness_centrality(G)
nx_cbc_time = time.time() - nx_cbc_time
print(f"custom cbc time : {custom_cbc_time:6.3f} sec")
print(f"networkx cbc time: {nx_cbc_time:6.3f} sec")
print(f"nx_cbc is {custom_cbc_time/nx_cbc_time} times faster than custom cbc")
print("=="*20)
# Compute np.corr
custom_cbc_np = np.array(list(custom_comm_bet_cent.values()))
custom_cbc_np /= np.linalg.norm(custom_cbc_np)
nx_cbc_np = np.array(list(nx_comm_bet_cent.values()))
nx_cbc_np /= np.linalg.norm(nx_cbc_np)
corr = np.correlate(custom_cbc_np, nx_cbc_np)[0]
print(f"corr: {corr:%}")
ustom cbc time : 1.227 sec
networkx cbc time: 0.015 sec
nx_cbc is 83.44528754641114 times faster than custom cbc
========================================
corr: 97.839404%
wrap-up
- ์๊ฒ ๊ฐ์ผ๋ฉด์๋, ์ค๊ฐ์ค๊ฐ ํท๊ฐ๋ฆฝ๋๋ค. linear algebra๋ฅผ ๋๋ฌด ๋ฉ๋ฆฌํ์ด์ ๊ทธ๋์ ใ ใ
reference
GitHub์์ ์ด ๊ธ์ ๋งํฌ๋ค์ด ์๋ณธ ๋ณด๊ธฐ & ์์ ์ ์src/content/posts/2020-02-04-communicability_between_cent
๐ ์ฐ๊ด ์ง์ ํ๋ธ:๐ python-libs ์นดํ
๊ณ ๋ฆฌ๐ธ NetworkX ์ปค๋ฆฌํ๋ผ#python#python-libs#networkx