Label Propagation
Label propagation是基于标传播的一种社区划分算法。Label Propagation Algorithm简称LPA算法,也可以是说是一种划分小团体的算法。这种社区划分的方法有很多,LPA只是一种最简单的一种。比如,以微博为例,用户在微博上可以关注感兴趣的人,同样也会被其他人关注,这样用户和用户之间就存在了关系,使用LPA就可以对用户进行聚类操作,相同兴趣点的用户可以聚类在一起,划分一起之后就可以统一进行推荐了,这样就可以用LPA。
社区划分
社区结构指的就是在网络中由一些节点构成的特定分组,在同一个分组内的节点通过节点,之间的连接边紧密的连接在一起,而在分组和分组之间,其连接比较松散,称每一个分组就是一个社区。由上就可以知道社区是网络中节点的集合,这些节点内部连接较为紧密而外部连接较为稀疏。
在一个社区网络中每一个用户其实就是一个节点,用户之间通过互相关注关系构成了用户之间的社交关系,用户之间通过转发感兴趣的东西,从而就构成了用户之间的兴趣关系。通过将不同用户划分到不同的社区,使得每一个社区是都有不同的属性,比如兴趣,领域等等。而在两个兴趣之间的关系相对来说就比较弱一些的就被分成了两个社区,这两个社区之间的相对连接会较为稀疏。比如:
黑圈里面的相对连接比较稠密,所以可以作为一个社区。可以看到整个网络被分成了3个圈,各个社区之间的联系就比较稠密。
社区划分算法
假设在一个网络里面,每一个样本只能是属于一个社区的,那么这样的问题就称为非重叠社区划分。在非重叠社区划分算法里面,有很多的方法:①基于模块度优化的社区划分。②基于谱分析的社区划分算法。③基于信息论的社区划分算法。④基于标签传播的社区划分算法。比较经典的应该算是基于模块度优化的社区划分算法了,其基本思想是将社区划分问题转换成了模块度函数的优化,而模块度是对社区划分算法结果的一个很重要的衡量标准。在实际求解的过程中是不能直接求解的,所以通常是采用近似解法,根据求解方法不同可以分为以下几种方法:①凝聚方法,通过不断合并不同社区,实现对整个网络的社区划分,典型的方法有Newman快速算法,CNM算法和MSG-MV算法。②分裂方法,通过不断的删除网络的边来实现对整个网络的社区划分,典型的方法有GN算法。③直接近似求解模块度函数,通过优化算法直接对模块度函数进行求解,典型的方法有EO算法。
社区划分的评价标准
按照不同的划分算法,社区划分的结果可能会存在很多种,所以每一种社区划分的质量都是不一样的,为了可以度量社区划分的质量,于是便使用了模块度的衡量标准。模块度是在
区间上的一个实数,通过比较每一个社区内部的连接密度和社区与社区直接的连接密度,去度量社区划分的质量。若将连接比较稠密的点划分在一个社区中,这样模块度的值就会变大。最后模块度最大的一种划分方法就是最优的划分方法。
Label Propagation Algorithm
LPA是一种基于标签传播的局部社区划分。对于网络中的每一个节点,在初始阶段,Label Propagation算法对于每一个节点都会初始化一个唯一的一个标签。每一次迭代都会根据与自己相连的节点所属的标签改变自己的标签,更改的原则是选择与其相连的节点中所属标签最多的社区标签为自己的社区标签,这就是标签传播的含义了。随着社区标签不断传播。最终,连接紧密的节点将有共同的标签。 LPA算法的最大的优点就是算法的逻辑非常简单,相对于优化模块度算法的过程是非常快的。LPA算法利用自身的网络的结构指导标签传播,这个过程是无需任何的任何的优化函数,而且算法初始化之前是不需要知道社区的个数的,随着算法迭代最后可以自己知道最终由多少个社区。 假设对于一个节点
,其相邻节点为
,对于每一个节点,都有其对应的标签,标签代表的是该节点所属的社区。在算法迭代的过程中,节点
根据其邻居节点更新所属的社区。比如:
一开始c选择了a,因为大家的社区标签都是一样的,所以随机选择了一个,d也根据自己周围的邻居节点来确定标签数,最多的是a,所以就是d为a了,以此类推,最后就全部都是a了。
标签传播
和上诉的更新过程是类似的,标签传播也分两种传播方式,同步更新,异步更新。 同步更新:对于节点
,在第t代时,根据其所以节点在第t-1代的标签进行更新。也就是
其中
表示的就是节点
在第t代时的社区标签。函数
表示的就是取参数节点中社区标签最多的。但是问题来了,这种同步更新的方法会存在一个问题,会出现标签震荡。
虽然结果影响不是非常大,但是对于这种不断的震荡终归是不好的。而且很难停止,因为停止的条件就是当社区标签不再变化的时候终止。 异步更新:对于异步更新方式
这个算法就不会出现刚刚的标签震荡的情况了。 对于他们之间的权重关系,其实就是他们之间的重要程度,也就是用户之间通信的频繁程度,比如密友和陌生人之间权重肯定不一样,还有他们之间的互动程度也不一样。所以如果没有给定权重,那就只能强算了。
使用高斯距离来得到权重。之后就是权重相加,看看哪一个权重大了。
算法迭代终止条件
当网络中的每一个节点所属的社区不再改变的时候迭代就可以停止了,对于每一个节点,在其所有的邻居节点所属当前社区中,其所属的社区标签是最大的,即:如果用
来表示社区标签,
表示节点i所有邻居节点中社区标签为
的个数,则算法终止条件为:对于每一个节点
,如果节点i的社区标签为
,则:
这样就可以获得最终的社区。但是社区不是唯一的。
代码实现
前面两个是连接的点,最后一个是权重。
def loadData(filePath):
f = open(filePath)
vector_dict = {}
edge_dict = {}
for line in f.readlines():
lines = line.strip().split(" ")
for i in range(2):
if lines[i] not in vector_dict:
vector_dict[lines[i]] = int(lines[i])
edge_list = []
if len(lines) == 3:
edge_list.append(lines[1 - i] + ":" + lines[2])
else:
edge_list.append(lines[1 - i] + ":" + "1")
edge_dict[lines[i]] = edge_list
else:
edge_list = edge_dict[lines[i]]
if len(lines) == 3:
edge_list.append(lines[1 - i] + ":" + lines[2])
else:
edge_list.append(lines[1 - i] + ":" + "1")
edge_dict[lines[i]] = edge_list
return vector_dict, edge_dict
一开始标签都是唯一的,第二条是边。
def get_max_community_label(vector_dict, adjacency_node_list):
label_dict = {}
for node in adjacency_node_list:
node_id_weight = node.strip().split(":")
node_id = node_id_weight[0]
node_weight = int(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
sort_list = sorted(label_dict.items(), key=lambda d: d[1], reverse=True)
return sort_list[0][0]
得到邻居节点最多的社区标签数。
def get_max_community_label(vector_dict, adjacency_node_list):
label_dict = {}
for node in adjacency_node_list:
node_id_weight = node.strip().split(":")
node_id = node_id_weight[0]
node_weight = int(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
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 node in vector_dict.keys():
adjacency_node_list = edge_dict[node]
node_label = vector_dict[node]
label = get_max_community_label(vector_dict, adjacency_node_list)
if node_label >= label:
continue
else:
return 0
return 1
主函数。
def label_propagation(vector_dict, edge_dict):
t = 0
print('First Label: ')
while True:
if (check(vector_dict, edge_dict) == 0):
t = t + 1
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)
else:
break
return vector_dict
最后效果:
附上GitHub代码:https://github.com/GreenArrow2017/MachineLearning/tree/master/MachineLearning/Label%20Propagation
- appium+python自动化30-list定位(find_elements)
- python笔记4-遍历文件夹目录os.walk()
- 【专知国庆特刊-PyTorch手把手深度学习教程系列01】一文带你入门优雅的PyTorch
- python接口自动化14-multipart/form-data上传图片
- 【干货】RL-GAN For NLP: 强化学习在生成对抗网络文本生成中扮演的角色
- python接口自动化15-multipart/form-data表单提交
- appium+python自动化32-android_uiautomator定位进阶版
- appium+python自动化33-解锁九宫格(TouchAction)
- 用qemu中最少的代码实现一个kvm模拟器
- 关关的刷题日记07——Leetcode 26. Remove Duplicates from Sorted Array 方法1
- openstack如何扩展API之一:新添加API
- 值得收臧 | 从零开始搭建带GPU加速的深度学习环境(操作系统、驱动和各种机器学习库)
- python接口自动化16-multipart/form-data上传多个附件
- python接口自动化17-响应时间与超时(timeout)
- 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 数组属性和方法
- 放弃fastjson,拥抱Jackson
- Spring入门
- 贪心-HDU1789 Doing Homework again(活动安排问题)
- flink实战-实时计算平台通过api停止流任务
- JAVA初级岗面试知识点——基础篇
- flink实战-flink streaming sql 初体验
- flink实战教程-使用set实时计算当天网站uv
- 贪心-HDU3348 coins(钱币问题)
- 归并排序详解 -HDU4911 Inversion(逆序对)
- 数据结构与算法——稀疏数组
- Maven安装配置详细教程
- 数据结构与算法——冒泡排序
- MyBatis Generator逆向工程-你还在手写mapper吗?
- JSR303后端校验详解
- SSM整合开发实战 SSM-MALL