f_
frhyme.code
•python-libs•โฑ ์•ฝ 7๋ถ„ ์†Œ์š”

NetworkX: communicability betweenness centrality

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

๐Ÿ’กRELATED ARTICLES ยท ํ•จ๊ป˜ ์ฝ์œผ๋ฉด ์ข‹์€ ์—ฐ๊ด€ ํฌ์ŠคํŠธ

๊ธ€ ์ฃผ์†Œ๊ฐ€ ํด๋ฆฝ๋ณด๋“œ์— ๋ณต์‚ฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.