论文复现:《复杂网络中节点重要度评估的节点收缩方法》
背景介绍
我在做毕业论文实验的时候,需要用到凝聚度作为电力节点的重要度指标。在网上找到一篇博客,是用Matlab复现的,但是我运行了他写的代码之后,发现他的代码有点问题,采用论文中的算例得出来的结果跟论文中的结果不太一样,这是那篇博客的地址:matlab实现复杂网络中节点重要度评估的节点收缩方法。 于是我自己用python复现了这篇论文,采用与原文同样的算例后,结果跟论文中也是一致的。我所使用的为Python 3.6,所用的包为networkx 2.5.1。
论文中的基本理论
节点收缩
假设
v
i
v_i
vi是图
G
=
(
V
,
E
)
G=(V, E)
G=(V,E)中的一个节点,我们用
G
∗
v
i
G*v_i
G∗vi表示将节点
v
i
v_i
vi收缩后所得到的图。所谓将节点
v
i
v_i
vi收缩是指将与节点
v
i
v_i
vi相连接的
k
i
k_i
ki个节点都与节点
v
i
v_i
vi融合,即用一个新节点代替这
k
i
+
1
k_i+1
ki+1个节点,原先与它们关联的边现在都与新节点关联,如图1所示。
网络凝聚度
网络的凝聚度首先取决于网络中各个节点之间的联通能力,我们用节点之间的平均路径长度
l
l
l来衡量,即所有节点对之间最短距离的算数平均值。其次,网络的凝聚度还取决于网络中节点节点数目
n
n
n。例如在一个社会关系网里,人员之间联系越方便(
l
l
l越小)、人数越少(
n
n
n越小),整个网络的凝聚程度就越高。我们将网络的凝聚度定义为节点数
n
n
n与平均路径长度
l
l
l乘积的倒数。
定义1 我们称
∂
[
G
]
=
1
n
⋅
l
=
1
n
⋅
∑
i
≠
j
∈
V
d
i
j
n
(
n
−
1
)
=
n
−
1
∑
i
≠
j
∈
V
d
i
j
(1)
\partial[\boldsymbol G]=\frac{1}{n \cdot l}=\frac{1}{n \cdot \frac{{\sum_{i \neq j \in V} d_{i j}}}{n(n-1)}}=\frac{n-1}{\sum_{i \neq j \in V} d_{i j}}\tag {1}
∂[G]=n⋅l1=n⋅n(n−1)∑i=j∈Vdij1=∑i=j∈Vdijn−1(1)为图
G
G
G的凝聚度,其中
n
≥
2
n\geq2
n≥2,
d
i
j
d_{ij}
dij代表节点
i
i
i和
j
j
j之间的最短距离。
当
n
=
1
n=1
n=1时,我们令
∂
=
1
\partial=1
∂=1。显然
0
<
∂
≤
1
0<\partial\leq1
0<∂≤1,当网络中只有一个节点时,
∂
\partial
∂取最大值1。
节点重要度评估
定义2 我们称
I
M
C
(
v
i
)
=
1
−
∂
[
G
]
∂
[
G
∗
v
i
]
(2)
\boldsymbol {IMC}(v_i)=1-\frac {\partial[\boldsymbol G]}{\partial[\boldsymbol G*v_i]}\tag {2}
IMC(vi)=1−∂[G∗vi]∂[G](2)为节点
v
i
v_i
vi的重要度,其中
G
∗
v
i
G*v_i
G∗vi表示将节点
v
i
v_i
vi收缩后所得到的图。
由定义1和定义2我们可以得到:
I
M
C
(
v
i
)
=
1
−
∂
[
G
]
∂
[
G
∗
v
i
]
=
1
−
1
n
⋅
l
(
G
)
1
(
n
−
k
i
)
⋅
l
(
G
∗
v
i
)
=
n
⋅
l
(
G
)
−
(
n
−
k
i
)
⋅
l
(
G
∗
v
i
)
n
⋅
l
(
G
)
(3)
\boldsymbol {IMC}(v_i)=1-\frac {\partial[\boldsymbol G]}{\partial[\boldsymbol G*v_i]}=1-\frac{\frac {1} {n \cdot l(\boldsymbol G)}}{\frac {1} {(n-k_i) \cdot l(\boldsymbol G * v_i)}}=\frac {n \cdot l(\boldsymbol G)-(n-k_i) \cdot l(\boldsymbol G * v_i)} {n \cdot l(\boldsymbol G)}\tag{3}
IMC(vi)=1−∂[G∗vi]∂[G]=1−(n−ki)⋅l(G∗vi)1n⋅l(G)1=n⋅l(G)n⋅l(G)−(n−ki)⋅l(G∗vi)(3)又因为
1
≤
l
(
G
∗
v
i
)
<
l
(
G
)
1 \leq{l(\boldsymbol G*v_i)}<l(\boldsymbol G)
1≤l(G∗vi)<l(G),
k
i
≥
1
k_i\geq1
ki≥1,所以
0
<
1
n
<
I
M
C
(
v
i
)
≤
1
−
1
n
⋅
l
(
G
)
<
1
(4)
0<\frac 1n<\boldsymbol {IMC}(v_i)\leq{1-\frac {1}{n \cdot l(\boldsymbol G)}}<1 \tag{4}
0<n1<IMC(vi)≤1−n⋅l(G)1<1(4)当且仅当
v
i
v_i
vi为星型网络中的中心节点时,式(4)中等号成立。此时,
k
i
=
n
−
1
,
l
(
G
)
=
2
(
n
−
1
)
n
,
l
(
G
∗
v
i
)
=
1
,
I
M
C
(
v
i
)
=
1
−
1
n
⋅
l
(
G
)
=
1
−
1
2
(
n
−
1
)
k_i=n-1,l(\boldsymbol G)=\frac{2(n-1)}{n}, l(\boldsymbol G * v_i)=1,\boldsymbol {IMC}(v_i)=1-\frac{1}{ n \cdot l(\boldsymbol G)}=1-\frac{1}{2(n-1)}
ki=n−1,l(G)=n2(n−1),l(G∗vi)=1,IMC(vi)=1−n⋅l(G)1=1−2(n−1)1。
由式(3)可以看出,节点
v
i
v_i
vi的重要度取决于两个因素:一是节点
v
i
v_i
vi的连接度
k
i
k_i
ki,另外一个是节点
v
i
v_i
vi在网络中的位置。相同条件下,如果节点
v
i
v_i
vi的连接度
k
i
k_i
ki越大,则将该节点收缩以后网络中节点的数目就越少,网络的凝聚度就越大,该节点越重要。另外,如果节点
v
i
v_i
vi处于“要塞”位置,则很多节点对之间的最短路径都要经过该节点,那么当把
v
i
v_i
vi收缩以后网络的平均路径长度将大大减少,从而获得较大的网络凝聚度。
算法伪代码
输入:
H
\boldsymbol H
H(邻接矩阵)
输出:
I
M
C
\boldsymbol {IMC}
IMC(节点重要度)
1)计算所有节点对之间的最短距离矩阵
D
=
[
d
i
j
]
D=[d_{ij}]
D=[dij] \\Floyd算法;
2)根据式(1)计算网络初始凝聚度
∂
[
G
]
\partial[\boldsymbol G]
∂[G];
3)
F
O
R
i
=
1
t
o
n
\bold{FOR} \quad i=1 \quad to \quad n
FORi=1ton \\主循环,评估所有节点重要度;
{ 计算节点
v
i
v_i
vi收缩后所有节点对之间的最短距离矩阵
D
(
i
)
=
[
D
s
t
(
i
)
]
D^{(i)}=[D^{(i)}_{st}]
D(i)=[Dst(i)];
根据式(1)计算节点
v
i
v_i
vi收缩后网络的凝聚度
∂
[
G
∗
v
i
]
\partial[\boldsymbol G*v_i]
∂[G∗vi];
根据式(2)计算
I
M
C
(
v
i
)
\boldsymbol {IMC}(v_i)
IMC(vi);
}
论文中的算例
图2为论文所采用的算例的拓扑结构图,该网络中有10个节点,10条边。节点收缩后的结果如图3所示。
其中
(
a
)
(a)
(a)为节点
v
1
v_1
v1、
v
2
v_2
v2、
v
9
v_9
v9或
v
10
v_{10}
v10收缩后的图;
(
b
)
(b)
(b)为节点
v
3
v_3
v3或
v
8
v_8
v8收缩后的图;
(
c
)
(c)
(c)为节点
v
4
v_4
v4或
v
7
v_7
v7收缩后的图;
(
d
)
(d)
(d)为节点
v
5
v_5
v5或
v
6
v_6
v6收缩后的图。
节点 | 连接度 | 节点收缩法 |
---|---|---|
v 1 v_1 v1 | 1 | 0.1492 |
v 2 v_2 v2 | 1 | 0.1492 |
v 3 v_3 v3 | 3 | 0.4454 |
v 4 v_4 v4 | 3 | 0.4706 |
v 5 v_5 v5 | 2 | 0.2005 |
v 6 v_6 v6 | 2 | 0.2005 |
v 7 v_7 v7 | 3 | 0.4706 |
v 8 v_8 v8 | 3 | 0.4454 |
v 9 v_9 v9 | 1 | 0.1492 |
v 10 v_{10} v10 | 1 | 0.1492 |
代码实现
节点收缩法子程序
节点收缩法的子程序主要作用是:生成原始网络的每个节点收缩后的网络的集合。采用的方法是,先找出节点 i i i的邻居节点集合 S S S,然后在网络中删除节点 i i i,并将节点 i i i的所有节点都更改为 i i i,最后删除节点 i i i收缩后的网络中的重复边。
# 输入为原始状态下的网络图,输出节点收缩后的图的集合
def node_shrink(Graph): # 节点收缩法
Graphs = []
for i in list(Graph.nodes): # 计算每个节点收缩后的图
subGraph = nx.Graph()
neighboor_nodes = [n for n in Graph.neighbors(i)] # i节点的邻居节点
Graph_int = copy.deepcopy(Graph) # 深拷贝Graph
Graph_int.remove_node(i) # 删除节点i
remove_edge = list([list(i) for i in Graph_int.edges]) # 删除节点i后,图中的边
for j in range(len(remove_edge)): # 将节点i的邻居节点都改成节点i实现节点收缩
for k in range(len(neighboor_nodes)):
if remove_edge[j][0] == neighboor_nodes[k]:
remove_edge[j][0] = i
elif remove_edge[j][1] == neighboor_nodes[k]:
remove_edge[j][1] = i
else:
continue
subGraph.add_edges_from(remove_edge)
subGraph.name = str(i) # 给图赋属性,排序用
Graphs.append(subGraph)
# 冒泡排序
for i in range(len(Graphs)):
# Last i elements are already in place
for j in range(0, len(Graphs) - i - 1):
if int(Graphs[j].name) > int(Graphs[j + 1].name):
Graphs[j], Graphs[j + 1] = Graphs[j + 1], Graphs[j]
return Graphs # 返回排序后节点收缩图的集合
重要度子程序
按照式(1)计算原始网络和节点 i i i收缩后的网络的凝聚度,然后按照式(2)计算节点 i i i对应的重要度指标。
def IMCs(graph_int, Graphs): # 计算重要度
njd_int = 1 / (len(list(graph_int.nodes)) * nx.average_shortest_path_length(graph_int)) # 原始网络凝聚度
IMCs = []
for graph in Graphs:
njd = 1 / (len(list(graph)) * nx.average_shortest_path_length(graph))
IMC = 1 - njd_int / njd
IMCs.append(IMC)
return IMCs
测试主程序
将论文中算例的网络拓扑结构用networx包中的Gaph函数函数表示,并计算节点重要度指标。
if __name__ == '__main__':
# 论文测试算例
edges = [(1, 3), (2, 3), (3, 4), (4, 5), (4, 7), (5, 6), (6, 7), (7, 8), (8, 9), (8, 10)]
Graph = nx.Graph()
for i in range(len(edges)):
Graph.add_edge(edges[i][0], edges[i][1])
Graph.add_edges_from(edges)
shrink_Graphs = node_shrink(Graph) # 节点收缩后的图
IMCs = IMCs(Graph, shrink_Graphs) # 节点重要度
计算结果
程序的计算结果如图4所示,可以看出跟论文中的结果是一致的。
引用
[1]谭跃进, 吴俊, 邓宏钟. 复杂网络中节点重要度评估的节点收缩方法[J]. 系统工程理论与实践, 2006, 26(11):6.