【ネットワークの中心性】vol.5 固有ベクトル中心性
シリーズの目次
ネットワーク構造をどう組み込むか
前回の記事では,次数中心性はシンプルで計算しやすい反面,自分の近傍のローカルな情報しか扱えず,ネットワーク全体の構造が持つグローバルな情報を無視してしまうため,ノードのランキング機能を果たせない,あるいはノードを正当に評価できないという問題があることを確認しました.
もう一つ次数中心性の粗さを挙げるとすれば,すべてのつながりを同等に評価している点があります.現実のネットワークにおいて,自分の近傍ノードの重要性がすべて等しいとは限りません.多くの場合,あるノードの重要性はその近傍ノード自体がどれだけ重要かに依存します.極端な例を挙げれば,世界にたった一人しか友達がいなかったとしても,その友達が首相や大統領レベルの人であれば,自分の重要性は比較的高くなるわけです.中心性を計算するには,友達が何人いるかだけでなく,誰を知っているかも加味すべきです.このように,中心性は重要なノードにつながっているノードほど重要であるという再帰性 (recursive property) を持つことになります.
この再帰性を考慮して次数中心性を拡張したものが固有ベクトル中心性 (eigenvector centrality) です [Bonacich, 1987].単純に友達の数をスコアとして与えるのではなく,友達の持つ中心性に比例したスコアをノードに割り振っていきます.あるノードのスコアを計算するために,他すべてのノードのスコアをすでに知っている必要があるというのは一見堂々巡りに思えますが,それを綺麗に解決してくれるのが固有ベクトルです.
【無向グラフ】固有ベクトル中心性
固有ベクトル中心性の基本的なアイデアを理解するために,まずは無向グラフで固有ベクトル中心性を定義します.簡単のため,ここでは連結な無向グラフを考えます.無向グラフ
図1:固有ベクトル中心性の概念図
固有ベクトル中心性の再帰性から,
無向グラフが連結であるとき隣接行列は既約なので,ひとまず比例定数を
と書けます[1].さらに,隣接行列を使えば
となります[2].
-
の持つエッジの本数が多いときi -
の隣接ノードの中心性が高いときi
に大きくなることがわかります.1つ目は次数中心性と変わりませんが,2つ目で重要なノードとつながっているほど重要であるというアイデアを回収しています.このように定義された固有ベクトル中心性では,控えめな中心性を持つ友達をたくさん持つか,高い中心性を持つ少数の友達を持つか(あるいはその両方)のどちらかによって,高い中心性を達成することができます.友達がたくさんいることで影響力を持つこともあれば,友達が少なくても友達の影響力が大きければ影響力があると見なせるため,固有ベクトル中心性の定義は妥当だと言えるでしょう.
ところで,
となります.これは固有ベクトルの定義そのものです.再帰性を考慮して次数中心性を拡張していくと,実は隣接行列の固有ベクトルを求める問題に帰着するというわけです.さらに,
また,今回のようにネットワークが連結であれば,隣接行列は既約ですので
中心性指標の目的は通常,ネットワーク内で最も重要なノードを選び出すか,あるいは最も重要なノードから最も重要でないノードにランク付けすることなので,重要なのは異なるノードの相対的なスコアであって,絶対的な数値ではありません.したがって,中心性指標自体は,それが隣接行列の固有ベクトルであるならば,スカラー倍の範囲内で任意にとられても構わないわけです.
ネットワーク全体の構造を反映しているか
再帰性を考慮した結果,隣接行列の支配的な固有ベクトルとして定義される固有ベクトル中心性ですが,ネットワーク構造が持つグローバルな情報を無視するという次数中心性の問題は解決できているのでしょうか.定義をもう一度確認すると,ノード
でした.この関係が任意の
【有向グラフ】固有ベクトル中心性
有向グラフではハブ中心性とオーソリティ中心性という2つの評価軸を持つ中心性を考えることができるのでした.固有ベクトルについてもハブベース固有ベクトル中心性 (hub-based eigenvector centrality) とオーソリティベース固有ベクトル中心性 (authority-based eigenvector centrality) を定義できます.以下,有向グラフ
ハブベース固有ベクトル中心性
図2:ハブベース固有ベクトル中心性の概念図
ノード
と定義されます.このように
-
から出るエッジの本数(出近傍i の数)が多いときN_G^{\text{out}}(i) -
の出近傍の中心性i が高いときe_j
に大きくなります.
と書け,さらにこれをベクトル形式で書くと
と変形でき,ハブベース固有ベクトル中心性の計算は,隣接行列の支配的な右固有ベクトルを求める問題に帰着します.
証明
オーソリティベース固有ベクトル中心性
図3:オーソリティベース固有ベクトル中心性の概念図
ノード
と定義されます.このように
-
に入ってくるエッジの本数(入近傍j の数)が多いときN_G^{\text{in}}(j) -
の入近傍の中心性j が高いとき\varepsilon_i
に大きくなります.
と書け,さらにこれをベクトル形式で書くと
と変形でき,オーソリティベース固有ベクトル中心性の計算は,隣接行列の支配的な左固有ベクトルを求める問題に帰着します.
Python による実装
隣接行列
を活用して固有ベクトル中心性を計算することができます.
が成り立ちます.
しかし,現実のネットワークで原始性という強い条件を満たすのは難しいため,ここでは代替案として固有値問題を解くアルゴリズムであるべき乗法 (power method) を使用します.まず,隣接行列 spectral_radius()
関数を定義します.
import numpy as np
def spectral_radius(M):
"""
Compute the spectral radius of M.
"""
return np.max(np.abs(np.linalg.eigvals(M)))
この spectral_radius()
関数を使って固有ベクトル中心性を計算する eigenvector_centrality()
関数を定義します.計算される支配的な固有ベクトルは,和が
def eigenvector_centrality(A, k=40, authority=False):
"""
Computes the dominant eigenvector of A using the power method.
Parameters
----------
A : NumPy ndarray
Adjacency matrix representation of graph.
k : int (default: 40)
How many times A is to be "powered".
authority : bool (default: False)
If authority = True, A is replaced by its transpose.
Returns
-------
k : NumPy ndarray
Eigenvector centrality of A.
"""
A_temp = A.T if authority else A
n = len(A_temp)
r = spectral_radius(A_temp)
e = r**(-k) * (np.linalg.matrix_power(A_temp, k) @ np.ones(n))
return e / np.sum(e)
前回の記事で次数中心性の粗さを指摘するために例示したネットワークは,図4のように辺境の名士(1,2,3番)が真の名士(0番)を中心につながったネットワークでした.0,1,2,3番のノードの次数はすべて3ですから,本当は他3つのノードをまとめる0番を高く評価したいのに,次数中心性はそれらすべてを同等に扱ってしまうという問題があったのでした.
図4: 辺境の名士が真の名士を中心につながったネットワーク
再びこのネットワークを用いて,固有ベクトル中心性でこの問題を解決できるか確認します.
図5:次数中心性(左)と固有ベクトル中心性(右)
code
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
次数中心性の計算には,前回定義した degree_centrality()
関数を使用しています.
def degree_centrality(A, authority=False):
A_temp = A.T if authority else A
N = len(A_temp)
return A_temp@np.ones(N)
中心性を格納するデータフレームを作成する centrality_plot_data()
関数を定義します.
def centrality_plot_data(nodes, centrality_measures):
df = pd.DataFrame({'node': nodes,
'centrality':centrality_measures,
'color': '#69b3a2'
})
return df
次数中心性と固有ベクトル中心性を比較します.
## 辺境の名士
# エッジリスト
edge_lst = [(0, 1), (0, 2), (0, 3), (1, 4), (1, 5), (2, 6), (2, 7), (3, 8), (3, 9)]
g = gt.Graph(directed=False) # グラフを生成
g.add_edge_list(edge_lst) # グラフにエッジを追加
# グラフを隣接行列に変換
A = gt.adjacency(g).toarray().T # graph-tool の隣接行列の定義は j --> i で a_{ij} = 1
degree = degree_centrality(A) # 次数中心性
eigenvector = eigenvector_centrality(A, authority=False) # 固有ベクトル中心性
nodes = [i for i in range(len(A))] # ノードリスト
centrality_measures = [degree, eigenvector] # 中心性リスト
ylabels = ['degree', 'eigenvector'] # 中心性名リスト
ylims = [(0, 5), (0, 0.25)]
fig, axes = plt.subplots(1, 2, figsize=(12,5))
axes = axes.flatten()
for i, ax in enumerate(axes):
df = centrality_plot_data(nodes, centrality_measures[i])
ax.bar('node', 'centrality', data=df, color=df["color"])
patch = mpatches.Patch(color=None, label=ylabels[i], visible=False)
ax.legend(handles=[patch], fontsize=18, loc="upper left", handlelength=0, frameon=False)
ax.set_xlabel("node", fontsize=18)
ax.tick_params(labelsize=14)
ax.set_xticks([i for i in range(10)])
if ylims[i] is not None:
ax.set_ylim(ylims[i])
fig.tight_layout()
図5が示すように,固有ベクトル中心性は次数中心性では捉えられなかった0番の重要性をしっかり評価しており,次数中心性の問題点を解決できていることがわかります.また,ネットワークが完全グラフに近い場合はどのノードも同じような次数になりランキング機能を果たせないという問題点も,図6が示す通り固有ベクトル中心性を使えば解決します.
図6:出/入次数中心性(上段)とハブ/オーソリティベース固有ベクトル中心性(下段)
出所)Stachurski et al. (2022)
固有ベクトル中心性の限界
実は固有ベクトル中心性にも致命的な欠点が存在します.固有ベクトル中心性は有向グラフが強連結であれば必ず定義できますが,多くの現実の有向ネットワークにおいて強連結性は満たされません.この強連結性の破れが望ましくない結果をもたらします.
図7:ハブ(左)とオーソリティ(右)
出所)Stachurski et al. (2022)
図7は中心性の2つの考え方を説明するために使用したものです.ハブ中心性で評価すると左のハブは高く評価され,オーソリティ中心性で評価すると右のオーソリティは高く評価されるということでした.ここで,少し見方を変えてみます.ハブはたくさんの出近傍を持っていますが,入近傍はないので,入次数が
では,シンクをハブベース固有ベクトル中心性で,ソースをオーソリティベース固有ベクトル中心性で評価するとどうなるのでしょうか.シンクのハブベース固有ベクトル中心性は常に
相手の気持ちを考えずにアピールばかりしていても,誰からも見向きもされなければオーソリティとしては評価されず,いくら自分が人気だからといって,集まってくる人たちに全く手を差し伸べないとハブとしては評価されないということです.使用した評価軸が自分の性質の真逆なので,評価されないのは当然といえば当然です.しかし実は,固有ベクトル中心性において,ハブは相手からのエッジが1本もなければハブとしても評価されず,オーソリティは相手にエッジを1本も張らなければオーソリティとしても評価されないという事態が起こりえます.例として図8の強連結でない有向グラフを考えます.
import graph_tool.all as gt
edge_lst = [(0, 1), (0, 2), (0, 3), (1, 2)] # エッジリスト
g = gt.Graph(directed=True) # グラフを生成
g.add_edge_list(edge_lst) # グラフにエッジを追加
gt.graph_draw(g, vertex_text=g.vertex_index, output_size=(300, 300)); # グラフを可視化
図8:強連結でない有向グラフ
図8でハブベース固有ベクトル中心性を考えます.明らかに0番のノードはハブなのでグラフ内で最高のハブ中心性を持っていそうです.まず,シンクである2番と3番のノードの中心性は
で
オーソリティベースの固有ベクトル中心性についても考えてみます.2番のノードはオーソリティなので,グラフ内で最高のオーソリティ中心性を持っていて欲しいところです.ソースである0番のノードの中心性は
当然,図7の有向グラフに対して先ほど実装した eigenvector_centrality()
関数を使っても欠損値が返ってきます.
import pandas as pd
# グラフを隣接行列に変換
A = gt.adjacency(g).toarray().T # graph-tool の隣接行列の定義は j --> i で a_{ij} = 1
out_degree = degree_centrality(A) # 出次数
in_degree = degree_centrality(A, True) # 入次数
eigen_hub = eigenvector_centrality(A, authority=False) # ハブ固有ベクトル
eigen_authority = eigenvector_centrality(A, authority=True) # オーソリティ固有ベクトル
# データフレームにまとめる
df = pd.DataFrame({"out_degree": out_degree,
"eigen_hub": eigen_hub,
"in_degree": in_degree,
"eigen_authority": eigen_authority})
df
index | out_degree | eigen_hub | in_degree | eigen_authority |
---|---|---|---|---|
0 | 3.0 | NaN | 0.0 | NaN |
1 | 1.0 | NaN | 1.0 | NaN |
2 | 0.0 | NaN | 2.0 | NaN |
3 | 0.0 | NaN | 1.0 | NaN |
以上から,固有ベクトル中心性ではハブベースであれオーソリティベースであれ,ソースやシンクが存在するような強連結でない有向グラフに対しては,エッジをたくさん持つのに中心性が
次回予告
本記事では,固有ベクトル中心性の定義と特徴を確認し,Python で無向グラフ(有向グラフ)の(ハブ/オーソリティベース)固有ベクトル中心性を計算する eigenvector_centrality()
関数を実装しました.実装した関数を使って,真の名士の周りに辺境の名士が集まった無向ネットワークの固有ベクトル中心性を計算した結果,固有ベクトル中心性は次数中心性の問題点を解決していることが確認できました.しかし,強連結でない有向グラフに対しては,他とつながっているのに中心性が
次回第6回は,固有ベクトル中心性の欠陥をある簡単なアイデアで解決する Katz 中心性を見ていきます.
参考文献
- Bonacich, P. (1987). Power and centrality: A family of measures. American journal of sociology, 92(5), 1170-1182.
- John Stachurski and Thomas J. Sargent. Economic Networks: Theory and Computation (QuantEcon, 2022). URL https://networks.quantecon.org/ .
-
隣接行列が既約であれば,ペロン=フロベニウスの定理より
なので定義可能です. ↩︎\rho(A)>0 -
どうしてこのように書けるかは,上の概念図で仮に新たなノード
が孤立した状態で参入したとき,エッジ4 が存在せず(i,4) となることからわかると思います. ↩︎a_{i4} = 0 -
証明は有向グラフのハブベース固有ベクトル中心性で行なっています. ↩︎
-
出次数が
のノード(シンク)のハブベース固有ベクトル中心性が常に0 であることは容易に示せます.任意のノード0 の出次数がi であるとき,0 が成り立ちます.k_i^{\text{out}}=\sum_j a_{ij}=0 よりa_{ij}\geqslant0 .よって,a_{ij}=0~~\forall j . ↩︎e_j = \rho(A)^{-1}\sum_ja_{ij}e_j=0 -
任意のノード
の入次数がj であるとき,0 より|N_G^{\text{in}}(j)|=0 式の右辺が(8) となるため,0 .シンクについてもこの方法で示せば早かったですね... ↩︎\varepsilon_j = 0 -
逆に,グラフが強連結であれば固有ベクトル中心性が必ず定義できるのは,どのノードも出ていくエッジと入ってくるエッジを少なくとも1本ずつ持っているからだということがわかります. ↩︎
Discussion