社团划分——有向图的Label Propagation算法
在博文社区划分——Label Propagation中,介绍了Label Propagation社区划分算法的基本原理,基本的Label Propagation算法是针对无向图的社区划分算法。
一、基本Label Propagation算法原理
对于网络中的每一个节点,在初始阶段,Label Propagation算法对每一个节点一个唯一的标签,在每一个迭代的过程中,每一个节点根据与其相连的节点所属的标签改变自己的标签,更改的原则是选择与其相连的节点中所属标签最多的社区标签为自己的社区标签,这便是标签传播的含义。随着社区标签的不断传播,最终紧密连接的节点将有共同的标签。
其中,标签的异步更新方式如下:
Cx(t)=f(Cxi1(t),⋯,Cxim(t),Cxi(m+1)(t−1),⋯,Cxik(t−1))
C_xleft ( t right )=f
Label Propagation算法的过程如下:
- 对网络中的每一节点初始化其所属社区标签,如对于节点xx,初始化其社区标签为Cx(0)=xC_x
- 设置代数tt;
- 对于网络中的节点设置其遍历顺序和节点的集合XX;
- 对于每一个节点x∈Xxin X,令Cx(t)=f(Cxi1(t),⋯,Cxim(t),Cxi(m+1)(t−1),⋯,Cxik(t−1))C_x
- 判断是否可以迭代结束,如果否,则设置t=t+1t=t+1,重新遍历。
二、有向图的Label Propagation算法
1、有向图
有向图是指图中的边是带有方向的图。对于有向图,每两个节点之间的边的条数是两条,分别为流出的边和流入的边,其流出边的总数为出度,流入边的总数为入度,如下图的有向图:
(图片来自百度百科)
对于节点5,其出度为22,入度也为22。对于更多的有向图的知识,可参阅相关图论的书。
2、对于Label Propagation算法的修正
要使得Label Propagation算法能够求解有向图的社区划分,问题即变为如何将有向图转换成无向图。即如何定义有向图中两个节点之间的边的权重。对于这个问题,设计了如下的公式:
wi,j=αλi,j+βλj,i
w_{i,j}=alpha lambda _{i,j}+beta lambda _{j,i}
其中wi,jw_{i,j}表示的是节点jj对于节点ii的权重,λi,j表示的是节点ii到节点jj的权重,λj,i表示的是节点jj到节点ii的权重。通过参数α 和参数β 可以调节不同的权重比例。
通过如上的办法将有向图的Label Propagation算法转换成无向图的Label Propagation算法进行求解。
三、实验
对于如下的数据:
0 2 1
2 0 2
0 3 2
3 0 1
0 4 3
4 0 1
0 5 2
5 0 1
1 2 3
2 1 1
1 4 5
4 1 2
1 7 1
7 1 4
2 4 2
4 2 2
2 5 9
5 2 7
2 6 1
6 2 4
3 7 1
7 3 5
4 10 1
10 4 4
5 7 1
7 5 2
5 11 1
11 5 2
6 7 3
7 6 7
6 11 5
11 6 2
8 9 1
9 8 6
8 10 4
10 8 2
8 11 2
11 8 1
8 14 5
14 8 3
8 15 8
15 8 5
9 12 2
12 9 1
9 14 1
14 9 2
10 11 10
11 10 1
10 12 2
12 10 3
10 13 9
13 10 8
10 14 8
14 10 7
11 13 1
13 11 4
程序源码如下:
#####################################
# Author:zhaozhiyong
# Date:20160602
# Fun:Label Propagation
#####################################
import string
def loadData(filePath):
f = open(filePath)
vector_dict = {}
edge_dict_out = {}#out
edge_dict_in = {}#in
for line in f.readlines():
lines = line.strip().split("t")
if lines[0] not in vector_dict:
vector_dict[lines[0]] = string.atoi(lines[0])
if lines[1] not in vector_dict:
vector_dict[lines[1]] = string.atoi(lines[1])
if lines[0] not in edge_dict_out:
edge_list = []
if len(lines) == 3:
edge_list.append(lines[1] + ":" + lines[2])
edge_dict_out[lines[0]] = edge_list
else:
edge_list = edge_dict_out[lines[0]]
if len(lines) == 3:
edge_list.append(lines[1] + ":" + lines[2])
edge_dict_out[lines[0]] = edge_list
if lines[1] not in edge_dict_in:
edge_list = []
if len(lines) == 3:
edge_list.append(lines[0] + ":" + lines[2])
edge_dict_in[lines[1]] = edge_list
else:
edge_list = edge_dict_in[lines[1]]
if len(lines) == 3:
edge_list.append(lines[0] + ":" + lines[2])
edge_dict_in[lines[1]] = edge_list
f.close()
return vector_dict, edge_dict_out, edge_dict_in
def get_max_community_label(vector_dict, adjacency_node_list):
label_dict = {}
# generate the label_dict
for node in adjacency_node_list:
node_id_weight = node.strip().split(":")
node_id = node_id_weight[0]
node_weight = float(node_id_weight[1])
if vector_dict[node_id] not in label_dict:
label_dict[vector_dict[node_id]] = node_weight
else:
label_dict[vector_dict[node_id]] += node_weight
# find the max label
sort_list = sorted(label_dict.items(), key = lambda d: d[1], reverse=True)
return sort_list[0][0]
def check(vector_dict, edge_dict):
#for every node
for node in vector_dict.keys():
adjacency_node_list = edge_dict[node]
node_label = vector_dict[node]#suject to
label_check = {}
for ad_node in adjacency_node_list:
node_id_weight = ad_node.strip().split(":")
node_id = node_id_weight[0]
node_weight = node_id_weight[1]
if vector_dict[node_id] not in label_check:
label_check[vector_dict[node_id]] = float(node_weight)
else:
label_check[vector_dict[node_id]] += float(node_weight)
#print label_check
sort_list = sorted(label_check.items(), key = lambda d: d[1], reverse=True)
if node_label == sort_list[0][0]:
continue
else:
return 0
return 1
def label_propagation(vector_dict, edge_dict_out, edge_dict_in):
#rebuild edge_dict
edge_dict = {}
for node in vector_dict.iterkeys():
out_list = edge_dict_out[node]
in_list = edge_dict_in[node]
#print "node:", node
#print "out_list:", out_list
#print "in_list:", in_list
#print "------------------------------------------------"
out_dict = {}
for out_x in out_list:
out_xs = out_x.strip().split(":")
if out_xs[0] not in out_dict:
out_dict[out_xs[0]] = float(out_xs[1])
in_dict = {}
for in_x in in_list:
in_xs = in_x.strip().split(":")
if in_xs[0] not in in_dict:
in_dict[in_xs[0]] = float(in_xs[1])
#print "out_dict:", out_dict
#print "in_dict:", in_dict
last_list = []
for x in out_dict.iterkeys():
out_x = out_dict[x]
in_x = 0.0
if x in in_dict:
in_x = in_dict.pop(x)
result = out_x + 0.5 * in_x
last_list.append(x + ":" + str(result))
if not in_dict:
for x in in_dict.iterkeys():
in_x = in_dict[x]
result = 0.5 * in_x
last_list.append(x + ":" + str(result))
#print "last_list:", last_list
if node not in edge_dict:
edge_dict[node] = last_list
#initial, let every vector belongs to a community
t = 0
#for every node in a random order
while True:
if (check(vector_dict, edge_dict) == 0):
t = t+1
print "----------------------------------------"
print "iteration: ", t
for node in vector_dict.keys():
adjacency_node_list = edge_dict[node]
vector_dict[node] = get_max_community_label(vector_dict, adjacency_node_list)
print vector_dict
else:
break
return vector_dict
if __name__ == "__main__":
vector_dict, edge_dict_out, edge_dict_in = loadData("./cd_data.txt")
print vector_dict
print edge_dict_out
print edge_dict_in
#print "original community: ", vector_dict
vec_new = label_propagation(vector_dict, edge_dict_out, edge_dict_in)
print "---------------------------------------------------------"
print "the final result: "
for key in vec_new.keys():
print str(key) + " ---> " + str(vec_new[key])
最终的结果:
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 深入 TypeScript 中的子类型、逆变、协变,进阶 Vue3 源码前必须搞懂的。
- Vue3 + TypeScript 实现递归菜单组件
- TypeScript 4.1 新特性:字符串模板类型,Vuex 终于有救了?
- TS 4.1 新特性实现 Vuex 无限层级命名空间的 dispatch 类型推断。
- egg.js踩坑记录(一)开始篇
- VUI创建日志(二)——防抖节流组件的实现
- 为你的VuePress博客添加GitTalk评论
- Go 中 Set 的实现方式
- Go 译文之词法分析与解析 Part Three
- React-Native踩坑记
- 【译】成为优秀程序员(和人类)的101个技巧
- 谈谈ES6语法(汇总中篇)
- 谈谈ES6语法(汇总下篇)
- [译] JS 中 service workers 的简介
- 【译】如何大大简化你的Vuex Store