背景
· 由node和egde形成的网络图中,关系紧密的可以形成一个社区,其内部紧密,与外部连接稀疏。社区发现算法就是要检测网络结构中紧密的社区团。
· 用什么可以描述社团的紧密程度:模块度(modularity), louvain算法的核心思想就是最大化模块度。
模块度
· 以无权重无向图为例(无权重可以看成边权重都是1)
Q
=
1
2
m
∑
i
,
j
[
A
i
,
j
−
k
i
k
j
2
m
]
δ
(
c
i
,
c
j
)
Q = \frac{1}{2m}\sum_{i,j}[A_{i,j} - \frac{k_ik_j}{2m}]\delta (c_i,c_j)
Q=2m1∑i,j[Ai,j−2mkikj]δ(ci,cj)
其中,
A
i
,
j
A_{i,j}
Ai,j是指示函数,表示i,j之间是否有边;
δ
(
c
i
,
c
j
)
\delta (c_i,c_j)
δ(ci,cj)也是指示函数,表示i和j是否在一个社群;
k
k
k表示节点的度,也就是和几个node相连;
k
i
k
j
2
m
\frac{k_ik_j}{2m}
2mkikj表示在随机状态下,i和j相连的概率;
· Q的公式的化简过程:
Q
=
1
2
m
∑
i
,
j
[
A
i
,
j
−
k
i
k
j
2
m
]
δ
(
c
i
,
c
j
)
Q = \frac{1}{2m}\sum_{i,j}[A_{i,j} - \frac{k_ik_j}{2m}]\delta (c_i,c_j)
Q=2m1∑i,j[Ai,j−2mkikj]δ(ci,cj)
=
1
2
m
[
∑
i
,
j
A
i
,
j
−
∑
k
i
∑
k
j
2
m
]
δ
(
c
i
,
c
j
)
=\frac{1}{2m}[\sum_{i,j}A_{i,j} - \frac{\sum k_i\sum k_j}{2m}]\delta (c_i,c_j)
=2m1[∑i,jAi,j−2m∑ki∑kj]δ(ci,cj)
=
1
2
m
∑
c
[
∑
i
n
−
(
∑
t
o
t
)
2
2
m
]
=\frac{1}{2m}\sum_{c}[\sum in - \frac{(\sum tot)^2}{2m}]
=2m1∑c[∑in−2m(∑tot)2]
=
∑
c
[
∑
i
n
2
m
−
(
∑
t
o
t
2
m
)
2
]
=\sum_{c}[\frac{\sum in}{2m} - (\frac{\sum tot}{2m})^2]
=∑c[2m∑in−(2m∑tot)2]
其中in表示社团c内部的连接,tot表示社团的节点的所有连接;
louvain算法
1)将图中的每个节点看成一个独立的社区
2)对每个节点
i
i
i ,依次尝试把节点
i
i
i 分配到其每个邻居节点所在的社区,计算分配前与分配后的模块度变化 Δ ,并记录 Δ 最大的那个邻居节点,如果 Δ > 0,则把节点
i
i
i 分配 Δ 最大的那个邻居节点所在的社区,否则保持不变
3)重复2)直到所有节点的所属社区不再变化
4)将所有在同一个社区的节点压缩成一个新节点,社区内节点之间的边的权重转化为新节点的环的权重,社区间的边权重转化为新节点间的边权重
5)重复1)直到整个图的模块度不再发生变化
Δ
Q
\Delta Q
ΔQ = 把i并入c的模块度 - (之前c的模块度 + i作为单独社区的模块度)
所以,
Δ
Q
=
∑
c
[
∑
i
n
+
k
i
,
i
n
2
m
−
(
∑
t
o
t
+
k
i
2
m
)
2
]
−
∑
c
[
∑
i
n
2
m
−
(
∑
t
o
t
2
m
)
2
−
(
k
i
2
m
)
2
]
\Delta Q =\sum_{c}[\frac{\sum in+k_{i,in}}{2m} - (\frac{\sum tot + k_i}{2m})^2] - \sum_{c}[\frac{\sum in}{2m} - (\frac{\sum tot}{2m})^2 - (\frac{k_i}{2m})^2]
ΔQ=∑c[2m∑in+ki,in−(2m∑tot+ki)2]−∑c[2m∑in−(2m∑tot)2−(2mki)2]
疑问:如果c有指向自己的边是不是
∑
i
n
\sum in
∑in那项不能约掉
全部展开化简后(已手推):
Δ
Q
=
∑
c
[
k
i
,
i
n
2
m
−
∑
t
o
t
+
k
i
2
m
2
]
\Delta Q =\sum_{c}[\frac{k_{i,in}}{2m} - \frac{\sum tot + k_i}{2m^2}]
ΔQ=∑c[2mki,in−2m2∑tot+ki]
调包:networkx
pip install python-louvain
#Louvain算法
import matplotlib.pyplot as plt
import networkx as nx
from community import community_louvain
# 空手道俱乐部
G = nx.karate_club_graph()
com = community_louvain.best_partition(G)
#节点大小设置,与度关联
node_size = [G.degree(i)**1*20 for i in G.nodes()]
#格式整理
df_com = pd.DataFrame({'Group_id':com.values(),
'object_id':com.keys()}
)
# 统计每个团伙人数 并降序
df_com.groupby('Group_id').count().sort_values(by='object_id', ascending=False)
# 颜色设置
colors = ['DeepPink','orange','DarkCyan','#A0CBE2','#3CB371','b','orange','y','c','#838B8B','purple','olive','#A0CBE2','#4EEE94']*500
colors = [colors[i] for i in com.values()]
#使用 kamada_kawai_layout spring_layout 布局
plt.figure(figsize=(4,3),dpi=500)
nx.draw_networkx(G,
pos = nx.spring_layout(G),
node_color = colors,
edge_color = '#2E8B57',
font_color = 'black',
node_size = node_size,
font_size = 5,
alpha = 0.9,
width = 0.1,
font_weight=0.9
)
plt.axis('off')
plt.show()
参考:https://zhuanlan.zhihu.com/p/556291759