图网络算法—网络中的社区结构(一)

图网络算法—网络中的社区结构

1. 社区结构(Communities)引入

1.1 社区结构的定义

在Granovertter’s原理中认为,网络是由一些紧密相连的节点所组成的。如下图所示:
在这里插入图片描述

进一步,根据网络中不同节点之间连接的紧密程度,我们可以将网络视为是由不同的“簇”所组成,其中“簇”内的节点之间连接更加的紧密,不同“簇”之间的的节点之间的链接比较稀疏。我们将这种“簇”称为是网络中的社区结构。

1.2 模块度(Modularity)Q

为了评价对于网络结构划分之后的各个社区结构的紧密程度,我们定义一个模块度Q。进一步,假设我们将一个网络结构划分成不同的社区结构,所有的社区构成了集合S,而每一个社区用s来表示,则有:

QsS[(s)?(s)]Q ∝ ∑_{s∈S}[(实际在s中的边)-(期望在s中的边)]

Q∝s∈S∑?[(实际在s中的边)?(期望在s中的边)]

1.3 配置模型(Configuration Model)

首先,给定一个图G,包含n个节点和m条边,将其重构成一个图

GG'

G′,其中图G’和原始图G的度的分布是一致,但是图G’中的节点之间的连接是均匀随机的。我们可以将G’视为一个多子图的结构。如下图所示:
在这里插入图片描述

图中一共有4个节点,其中节点的度的分布和原始的图G是相同的,不同节点之间的连接是均匀随机的。

以节点i和节点j为例,我们期望的是节点i和节点j之间的边的数量满足一下的公式:

ki?kj2m=kikj2mk_i * \frac{k_j}{2m}=\frac{kikj}{2m}

ki??2mkj??=2mkikj?
其中

ki,kjk_i,k_j

ki?,kj?表示的是节点i,j的度,m表示的是整个原始图的边的数量。

进一步,根据对于所有点的连接的期望,我们可以计算出对于图G’中的边的期望:

12iNjNkikj2m=1212miNki(jNkj)=14m2m?2m=m\frac{1}{2}∑_{i∈N}∑_{j∈N}\frac{k_ik_j}{2m}=\frac{1}{2}\frac{1}{2m}∑_{i∈N} k_i(∑_{j∈N}k_j) =\frac{1}{4m}2m*2m=m

21?i∈N∑?j∈N∑?2mki?kj??=21?2m1?i∈N∑?ki?(j∈N∑?kj?)=4m1?2m?2m=m

根据上述的公式可以看出,生成的新的图

GG'

G′并没有增加或者减少原始图中的边的数量。

最后,我们对配置模型生成的不同的社区,计算关于整个图的模块度,则有:

Q(G,S)=12msSisjs(Aij?kikj2m)Q(G,S)=\frac{1}{2m}∑_{s∈S}∑_{i∈s}∑_{j∈s}(A_{ij}-\frac{k_ik_j}{2m})

Q(G,S)=2m1?s∈S∑?i∈s∑?j∈s∑?(Aij??2mki?kj??)

Aij={1ifij0A_{ij}=\begin{cases}1&if& i,j之间有边\\
0&其他\end{cases}

Aij?={10?if其他?i,j之间有边

其中

AijA_{ij}

Aij?表示节点i,j之间的权重,

kik_i

ki?,

kjk_j

kj?表示节点i,j之间的度,m表示图中边的数量。

2. Louvain 算法

2.1. 算法介绍

Louvain是基于模块(modularity)算法,通过模块的度来衡量一个社区连接的紧密程度。如果一个节点加入到某一个社区中会使得该社区模块的度最大程度上的增加,则该节点就应该属于该社区,如果一个节点加入到其他的社区中没有引起其他社区模块的度增加,则将该节点留在当前的社区之中。

2.2 模块度Q

Q=12mi,j[Aij?kikj2m]δ(ci,cj)Q=\frac{1}{2m}∑_{i,j}[A_{ij}-\frac{k_ik_j}{2m}]δ(c_i,c_j)

Q=2m1?i,j∑?[Aij??2mki?kj??]δ(ci?,cj?)

ci,cjc_i,c_j

ci?,cj?表示两个社区内部的所有节点。其中δ表示指示函数,如果两个社区结构是同一个,则值为1,否则值为0。

ki,kjk_i,k_j

ki?,kj?表示节点i,j的度。

根据δ函数的定义不难发现,模块度Q只有节点i,j在同一个社区内部的时候Q函数才会有作用,也就是说,Q的主要作用是用于衡量社区内部的紧密程度。进一步,可以对公式进行变形有:

Q=12m?i,j[Ai,j?kikj2m]δ(ci,cj)=12m[i,jAi,j?ikijkj2m]δ(ci,cj)=12mc[in?tot22m]Q=\frac{1}{2m}*∑_{i,j}[A_{i,j}-\frac{k_ik_j}{2m}]δ(c_i,c_j)=\\
\frac{}{}\\
\frac{1}{2m}[∑_{i,j}A_{i,j}-\frac{∑_{i}k_i∑_jk_j}{2m}]δ(c_i,c_j)=\\
\frac{}{}\\
\frac{1}{2m}∑_{c}[∑_{in}-\frac{∑_{tot^2}}{2m}]

Q=2m1??i,j∑?[Ai,j??2mki?kj??]δ(ci?,cj?)=?2m1?[i,j∑?Ai,j??2m∑i?ki?∑j?kj??]δ(ci?,cj?)=?2m1?c∑?[in∑??2m∑tot2??]

我们简单的来介绍一下上面的公式变形,首先将求和公式挪到括号之内,从而得到了第二步。然后,根据δ的特征,我们可以按照每一个社区进行计算,也就是最外面的

c∑_c

∑c?,在根据我们上面介绍的关于

Ai,jA_{i,j}

Ai,j?的特点,

i,jAi,j∑_{i,j}A_{i,j}

∑i,j?Ai,j?表示的就是社区内部的边的数量之和,这里使用

in∑_{in}

∑in?来表示,最后使用

tot2∑_{tot^2}

∑tot2?来替代

iki,jkj∑_ik_i,∑_jk_j

∑i?ki?,∑j?kj?的乘积,这里需要注意的是

ki,kjk_i,k_j

ki?,kj?的度不仅仅包括其节点i,j在社区内部的度,同时也包含与其他社区内的点之间度。

在Louvain算法中,其目标不是为了计算每一个社区的模块度,而是为了计算模块度的增加,也就是△Q。将一个节点i分配到某一个社区之后,社区的模块度变化为:

Q=[in+ki,in2m?(tot+ki2m)2]?[in2m?(tot2m)2?(ki2m)2]=[ki,in2m?totki2m2]△Q=[\frac{∑_{in}+k_{i,in}}{2m}-(\frac{∑_{tot}+k_i}{2m})^2]-[\frac{∑_{in}}{2m}-(\frac{∑_{tot}}{2m})^2-(\frac{k_i}{2m})^2]=[\frac{k_{i,in}}{2m}-\frac{∑_{tot}k_i}{2m^2}]

△Q=[2m∑in?+ki,in???(2m∑tot?+ki??)2]?[2m∑in???(2m∑tot??)2?(2mki??)2]=[2mki,in???2m2∑tot?ki??]

其中

ki,ink_{i,in}

ki,in?表示社区内部所有的节点和节点i之间的连接边的数量。

kik_i

ki?表示节点i的度。

2.3. 算法步骤

Louvain算法主要是两步迭代的设计:

  1. 一开始,每个原始节点都可以看成是一个独立的社区,社区内的连边权重为0,。
  2. 算法扫描数据中的所有节点,针对每一个节点遍历该节点的所有邻居节点,衡量把该节点加入其邻居节点所在的社区所带来的模块度的收益。并选择对饮最大收益的邻居节点,加入其所在的社区。这一个过程重复进行直到每一个节点的社区归属都不在发生变化。
  3. 对于上一步形成的社区进行折叠,每一个社区折叠成一个单点,分别计算这些新生成的“社区点”之间的连边权重,以及社区内的所有点之间的连边的权重之和。用于下一轮的迭代。(类似于K-means算法)

我们举一个例子来描述一下:

在这里插入图片描述
上图所示的是一个图的第一轮迭代的过程。初始化时一共有14个节点,将每一个节点看出是一个社区。然后进入第一步迭代,从0节点开始,扫描其他的节点发现在将1,2,4,5节点加入到0节点所属的社区之后,出现了模块度Q的增加,此时,将0,1,2,4,5归入到一个社区之内,同样的道理,将3,7,6归入到一个社区,将11,13,归入到一个社区,将8,9,10,12,14,15归入到一个社区,也就是整个图被分成了4个社区结构,社区内的模块度Q为社区内部所有的边的总数,不同社区之间的权重为不同社区之间边的总数。

下一步进入第二个步骤,此时,将每一个社区内部的节点进行折叠,生成每一个社区的表示节点(super-nodes),由上图的右侧表示,不同表示节点之间的连接权重就是不同社区的边的总数,表示节点与自身的连接权重是社区内部边的数量。

然后,进入到下一轮的迭代:

在这里插入图片描述
在第二轮迭代中,整个图被抽象成了社区的表示节点,具体的步骤和上一步类似,这里就不在进行赘述了。

2.4.算法描述

在这里插入图片描述
在这里插入图片描述

3 参考

  1. 斯坦福CS224Wd
  2. Louvain算法的介绍与利用Graphx的实现过程