您的位置:首页 > 理论基础 > 计算机网络

网络的介数中心性(betweenness)及计算方法

2016-04-16 15:14 3731 查看
昨天面试被问到betweenness的计算方法,很尴尬没有自己实现过。平时用的时候通常用Python的networkx包计算,具体算法之前还没了解过。复杂网络的教材通常就介绍了betweenness的意义与定义,直接从定义出发计算的复杂度达到O(n3)

这里介绍一个2001年brandes提出的算法”A faster algorithm for betweenness centrality”,在无权图上复杂度为O(mn),在有权图上复杂度在O(mn+nlogn),在网络稀疏的时候,复杂度接近O(n2).

betweenness定义

betweenness的直接定义式为:

C
4000
B(v)=∑s≠v≠t∈Vσst(v)σst

其中σst(v)表示经过节点v的s→t的最短路径条数,σst表示s→t的最短路径条数。

直观上来说,betweenness反映了节点v作为“桥梁”的重要程度。

为了方便,定义pair-dependency为

δst(v)=σst(v)σst



CB(v)=∑s≠v≠t∈Vδst(v)

如何计算σst

首先引入一个记号

Ps(v)={u∈V:{u,v}∈E,dG(s,v)=dG(s,u)+ω(u,v)}

意思就是从节点s到节点v的最短路径中v的前驱节点集。或者说如果从s→t的最短路径包含边(u,v),那么u属于这个集合。

我们会发现下诉关系式成立:∀s≠t,

σsv=∑u∈Ps(v)σsu

理解这个关系式并不难:s→v的最短路径必然先从s→u,再通过边(u,v)到达v,其中u是v的前驱节点。

下面的问题简单多了,对无权图调用BFS算法,对有权图调用Dijkstra’s算法,前者在O(m)时间内算出{σst|t∈V},后者时间为O(m+nlogn)

简单介绍下BFS为什么可以做。我们知道BFS遍历节点的顺序恰好是按照距离节点s的距离升序排列的,而节点u是v的前驱节点必然要求d(s,u)<d(s,v),因此按照BFS遍历顺序,到达节点v时,其前驱节点u的σsu必然已经计算好了。

计算CB

现在我们计算出所有的了σst,为了得到δst(v)我们可能还要计算σst(v),虽然可以通过下面的关系式计算,但是复杂度又上去了。

σst(v)={σsv⋅σvt0d(s,v)+d(v,t)=d(s,t)other

事实上我们并不关心具体的某个δst(v),我们想要的是

∑s,tδst(v)

为此定义

δs⋅(v)=∑t∈Vδst(v)

下面我们要说明下面这个关系式成立:

δs⋅(v)=∑w:v∈Ps(w)σsvσsw(1+δs⋅(w))

如果这个关系式成立的话,根据先驱关系,计算δs⋅(v)需要先计算δs⋅(w),而v是w的先驱,顺序恰好跟BFS相反,因此用个栈就可以了。

我们试图在节点w与它的前驱节点v建立关系。我们可以把通过节点w的最短路径分成两类

通过节点v的路径

不通过节点v的路径

为了推导方便,引入几个符号:δst(v,e)=σst(v,e)σst,σst(v,e)表示s→t最短路径通过节点v和边e的条数。

显然的我们有

δs⋅(v)=∑t∈V∑w:v∈Ps(w)δst(v,{v,w})=∑w:v∈Ps(w)∑t∈Vδst(v,{v,w})

s→t的通过w的最短路径为σst(w)=σswσwt,而σst(v,{v,w})=σsvσwt

后者是因为从s→t经过v,(v,w)要先到达v,然后走(v,w),最后从w→t.

这里我们得到t≠w时

δst(v,{v,w})=σsvσswσst(w)σst

t=w时,

δst(v,{v,w})=σsvσsw

这就有

∑w:v∈Ps(w)∑t∈Vδst(v,{v,w})=∑w:v∈Ps(w)⎛⎝σsvσsw+∑t∈V−{w}σsvσswσst(w)σst⎞⎠=∑w:v∈Ps(w)σsvσsw(1+δs⋅(w))

至此计算就完毕了。

总结

列举下主要计算步骤

选取源节点s做BFS计算σst

遍历过程中将节点推入栈中,同时保留每个节点作为其他节点前驱的集合。

用公式计算δs⋅(v)

代码

import networkx as nx
from Queue import Queue
G = nx.random_graphs.barabasi_albert_graph(100,3)
#algorithm from networkx
C = nx.centrality.betweenness_centrality(G,normalized=False)

CB = dict.fromkeys(G,0.0)
for s in G.nodes():
Pred = {w:[] for  w in G.nodes()}
dist = dict.fromkeys(G,None)
sigma = dict.fromkeys(G,0.0)
dist[s] = 0
sigma[s] = 1
Q = Queue()
Q.put(s)
S = []
while not Q.empty():
v = Q.get()
S.append(v)
for w in G.neighbors(v):
if dist[w] == None:
dist[w] = dist[v] + 1
Q.put(w)
if dist[w] == dist[v] + 1:
sigma[w] += sigma[v]
Pred[w].append(v)
delta = dict.fromkeys(G,0.0)
for w in S[::-1]:
for v in Pred[w]:
delta[v] += sigma[v]/sigma[w]*(1+delta[w])
if w != s:
CB[w] += delta[w]
for v in CB:
CB[v] /= 2.0

#compare with networkx's implements
print(sum(abs(CB[v]-C[v]) for v in G)) #1.59428026336e-13
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息