社团划分——Fast Unfolding算法

一、社区划分问题

1、社区以及社区划分

在社交网络中,用户相当于每一个点,用户之间通过互相的关注关系构成了整个网络的结构,在这样的网络中,有的用户之间的连接较为紧密,有的用户之间的连接关系较为稀疏,在这样的的网络中,连接较为紧密的部分可以被看成一个社区,其内部的节点之间有较为紧密的连接,而在两个社区间则相对连接较为稀疏,这便称为社团结构。

(Newman and Gievan 2004) A community is a subgraph containing nodes which are more densely linked to each other than to the rest of the graph or equivalently, a graph has a community structure if the number of links into any subgraph is higher than the number of links between those subgraphs.

如下图:

用红色的点和黑色的点对其进行标注,整个网络被划分成了两个部分,其中,这两个部分的内部连接较为紧密,而这两个社区之间的连接则较为稀疏。如何去划分上述的社区便称为社区划分的问题。

2、社区划分的算法

在社区划分问题中,存在着很多的算法,如由Newman和Gievan提出的GN算法,标签传播算法(Label Propagation Algorithm, LPA),这些算法都能一定程度的解决社区划分的问题,但是性能则是各不相同。总的来说,在社区划分中,主要分为两大类算法

  1. 凝聚方法(agglomerative method):添加边
  2. 分裂方法(divisive method):移除边

在后续的文章中,我们会继续关注不同的社区划分的算法,在这篇文章中,主要关注Fast Unfolding算法。

3、社区划分的评价标准

为了评价社区划分的优劣,Newman等人提出了模块度的概念,用模块度来衡量社区划分的好坏。简单来讲,就是将连接比较稠密的点划分在一个社区中,这样模块度的值会变大,最终,模块度最大的划分是最优的社区划分。

二、模块度的概念

1、模块度的公式

社区划分的目标是使得划分后的社区内部的连接较为紧密,而在社区之间的连接较为稀疏,通过模块度的可以刻画这样的划分的优劣,模块度越大,则社区划分的效果越好 ,模块度的公式如下所示:

Q=12m∑i,j[Ai,j−kikj2m]δ(ci,cj)

Q=\frac{1}{2m}\sum_{i,j}\left [ A_{i,j}-\frac{k_ik_j}{2m} \right ]\delta \left ( c_i,c_j \right )

其中,m=12∑i,jAi,j m = \frac{1}{2}\sum_{i, j}A_{i,j} 表示的是网络中的所有的权重,Ai,j A_{i,j}表示的是节点i i和节点j j之间的权重,ki=∑jAi,j k_i=\sum_{j}A_{i,j}表示的是与顶点i i连接的边的权重,ci c_i表示的是顶点被分配到的社区,δ(ci,cj) \delta \left ( c_i,c_j \right )用于判断顶点i i与顶点j j是否被划分在同一个社区中,若是,则返回1 1,否则,返回0 0。

2、模块度公式的简化形式

上述的模块度的计算可以得到以下的简化形式:

Q=∑c⎡⎣∑in2m−(∑tot2m)2⎤⎦

Q=\sum_{c}\left [ \frac{\sum_{in}}{2m}-\left ( \frac{\sum_ {tot}}{2m} \right )^2 \right ]

其中,∑in \sum_{in}表示的是社区c c内部的权重,∑tot \sum_ {tot}表示的是与社区c c内部的点连接的边的权重,包括社区内部的边以及社区外部的边。

3、模块度公式的解释

模块度(modularity)指的是网络中连接社区结构内部顶点的边所占的比例,减去在同样的社团结构下任意连接这两个节点的比例的期望值。

三、Fast Unfolding算法

1、Fast Unfolding算法的思路

模块度成为度量社区划分优劣的重要标准,划分后的网络模块度值越大,说明社区划分的效果越好,Fast Unfolding算法便是基于模块度对社区划分的算法,Fast Unfolding算法是一种迭代的算法,主要目标是不断划分社区使得划分后的整个网络的模块度不断增大。

2、Fast Unfolding算法的过程

Fast Unfolding算法主要包括两个阶段,如下图所示:

第一阶段称为Modularity Optimization,主要是将每个节点划分到与其邻接的节点所在的社区中,以使得模块度的值不断变大;第二阶段称为Community Aggregation,主要是将第一步划分出来的社区聚合成为一个点,即根据上一步生成的社区结构重新构造网络。重复以上的过程,直到网络中的结构不再改变为止。

具体的算法过程如下所示:

  1. 初始化,将每个点划分在不同的社区中;
  2. 对每个节点,将每个点尝试划分到与其邻接的点所在的社区中,计算此时的模块度,判断划分前后的模块度的差值ΔQ \Delta Q是否为正数,若为正数,则接受本次的划分,若不为正数,则放弃本次的划分;
    • 重复以上的过程,直到不能再增大模块度为止;
    • 构造新图,新图中的每个点代表的是步骤3中划出来的每个社区,继续执行步骤2和步骤3,直到社区的结构不再改变为止。
    • 注意:在步骤2中计算节点的顺序对模块度的计算是没有影响的,而是对计算时间有影响

      四、算法实现

      针对上图表示的网络,最终的结果为:

      可以使用下面的程序实现其基本的原理:

      import stringdef loadData(filePath):f = open(filePath)vector_dict = {}edge_dict = {}for line in f.readlines():lines = line.strip().split("\t")for i in xrange(2):if lines[i] not in vector_dict:#put the vector into the vector_dictvector_dict[lines[i]] = True#put the edges into the edge_dictedge_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_listelse: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_listreturn vector_dict, edge_dictdef modularity(vector_dict, edge_dict):Q = 0.0# m represents the total wightm = 0for i in edge_dict.keys():edge_list = edge_dict[i]for j in xrange(len(edge_list)):l = edge_list[j].strip().split(":")m += string.atof(l[1].strip())# cal community of every vector#find member in every communitycommunity_dict = {}for i in vector_dict.keys():if vector_dict[i] not in community_dict:community_list = []else:community_list = community_dict[vector_dict[i]]community_list.append(i)community_dict[vector_dict[i]] = community_list#cal inner link num and degreeinnerLink_dict = {}for i in community_dict.keys():sum_in = 0.0sum_tot = 0.0#vector numvector_list = community_dict[i]#print "vector_list : ", vector_list#two loop cal inner linkif len(vector_list) == 1:tmp_list = edge_dict[vector_list[0]]tmp_dict = {}for link_mem in tmp_list:l = link_mem.strip().split(":")tmp_dict[l[0]] = l[1]if vector_list[0] in tmp_dict:sum_in = string.atof(tmp_dict[vector_list[0]])else:sum_in = 0.0else:for j in xrange(0,len(vector_list)):link_list = edge_dict[vector_list[j]]tmp_dict = {}for link_mem in link_list:l = link_mem.strip().split(":")#split the vector and weighttmp_dict[l[0]] = l[1]for k in xrange(0, len(vector_list)):if vector_list[k] in tmp_dict:sum_in += string.atof(tmp_dict[vector_list[k]])#cal degreefor vec in vector_list:link_list = edge_dict[vec]for i in link_list:l = i.strip().split(":")sum_tot += string.atof(l[1])        Q += ((sum_in / m) - (sum_tot/m)*(sum_tot/m))return Qdef chage_community(vector_dict, edge_dict, Q):vector_tmp_dict = {}for key in vector_dict:vector_tmp_dict[key] = vector_dict[key]#for every vector chose it's neighborfor key in vector_tmp_dict.keys():neighbor_vector_list = edge_dict[key]for vec in neighbor_vector_list:ori_com = vector_tmp_dict[key]vec_v = vec.strip().split(":")#compare the list_member with ori_comif ori_com != vector_tmp_dict[vec_v[0]]:vector_tmp_dict[key] = vector_tmp_dict[vec_v[0]]Q_new = modularity(vector_tmp_dict, edge_dict)#print Q_newif (Q_new - Q) > 0:Q = Q_newelse:vector_tmp_dict[key] = ori_comreturn vector_tmp_dict, Qdef modify_community(vector_dict):#modify the communitycommunity_dict = {}community_num = 0for community_values in vector_dict.values():if community_values not in community_dict:community_dict[community_values] = community_numcommunity_num += 1for key in vector_dict.keys():vector_dict[key] = community_dict[vector_dict[key]]return community_numdef rebuild_graph(vector_dict, edge_dict, community_num):vector_new_dict = {}edge_new_dict = {}# cal the inner connection in every communitycommunity_dict = {}for key in vector_dict.keys():if vector_dict[key] not in community_dict:community_list = []else:community_list = community_dict[vector_dict[key]]community_list.append(key)community_dict[vector_dict[key]] = community_list# cal vector_new_dictfor key in community_dict.keys():vector_new_dict[str(key)] = str(key)# put the community_list into vector_new_dict#cal inner link numinnerLink_dict = {}for i in community_dict.keys():sum_in = 0.0#vector numvector_list = community_dict[i]#two loop cal inner linkif len(vector_list) == 1:sum_in = 0.0else:for j in xrange(0,len(vector_list)):link_list = edge_dict[vector_list[j]]tmp_dict = {}for link_mem in link_list:l = link_mem.strip().split(":")#split the vector and weighttmp_dict[l[0]] = l[1]for k in xrange(0, len(vector_list)):if vector_list[k] in tmp_dict:sum_in += string.atof(tmp_dict[vector_list[k]])inner_list = []inner_list.append(str(i) + ":" + str(sum_in))edge_new_dict[str(i)] = inner_list#cal outer link numcommunity_list = community_dict.keys()for i in xrange(len(community_list)):for j in xrange(len(community_list)):if i != j:sum_outer = 0.0member_list_1 = community_dict[community_list[i]]member_list_2 = community_dict[community_list[j]]for i_1 in xrange(len(member_list_1)):tmp_dict = {}tmp_list = edge_dict[member_list_1[i_1]]for k in xrange(len(tmp_list)):tmp = tmp_list[k].strip().split(":");tmp_dict[tmp[0]] = tmp[1]for j_1 in xrange(len(member_list_2)):if member_list_2[j_1] in tmp_dict:sum_outer += string.atof(tmp_dict[member_list_2[j_1]])if sum_outer != 0:inner_list = edge_new_dict[str(community_list[i])]inner_list.append(str(j) + ":" + str(sum_outer))edge_new_dict[str(community_list[i])] = inner_listreturn vector_new_dict, edge_new_dict, community_dictdef fast_unfolding(vector_dict, edge_dict):#1. initilization:put every vector into different communities#   the easiest way:use the vector num as the community numfor i in vector_dict.keys():vector_dict[i] = i#print "vector_dict : ", vector_dict#print "edge_dict : ", edge_dictQ = modularity(vector_dict, edge_dict)  #2. for every vector, chose the communityQ_new = 0.0while (Q_new != Q):Q_new = Qvector_dict, Q = chage_community(vector_dict, edge_dict, Q)community_num = modify_community(vector_dict)print "Q = ", Qprint "vector_dict.key : ", vector_dict.keys()print "vector_dict.value : ", vector_dict.values()Q_best = Qwhile (True):#3. rebulid new graph, re_run the second stepprint "edge_dict : ",edge_dictprint "vector_dict : ",vector_dictprint "\n rebuild"vector_dict, edge_new_dict, community_dict = rebuild_graph(vector_dict, edge_dict, community_num)#print vector_dictprint "community_dict : ", community_dictQ_new = 0.0while (Q_new != Q):Q_new = Qvector_dict, Q = chage_community(vector_dict, edge_new_dict, Q)community_num = modify_community(vector_dict)print "Q = ", Qif (Q_best == Q):breakQ_best = Qvector_result = {}for key in community_dict.keys():value_of_vector = community_dict[key]for i in xrange(len(value_of_vector)):vector_result[value_of_vector[i]] = str(vector_dict[str(key)])for key in vector_result.keys():vector_dict[key] = vector_result[key]print "vector_dict.key : ", vector_dict.keys()print "vector_dict.value : ", vector_dict.values()#get the final resultvector_result = {}for key in community_dict.keys():value_of_vector = community_dict[key]for i in xrange(len(value_of_vector)):vector_result[value_of_vector[i]] = str(vector_dict[str(key)])for key in vector_result.keys():vector_dict[key] = vector_result[key]print "Q_best : ", Q_bestprint "vector_result.key : ", vector_dict.keys()print "vector_result.value : ", vector_dict.values()if __name__ == "__main__":vector_dict, edge_dict=loadData("./cd_data.txt")fast_unfolding(vector_dict, edge_dict)
      

      参考文献

      1. Vincent D Blondel, Jean-Loup Guillaume, Renaud Lambiotte, Etienne Lefebvre, Fast unfolding of communities in large networks, in Journal of Statistical Mechanics: Theory and Experiment 2008 (10), P1000
      2. 社区发现算法FastUnfolding的GraphX实现 http://www.tuicool.com/articles/Jrieue

社团划分——Fast Unfolding算法相关推荐

  1. fast unfolding 算法——论文总结

    一.社区划分问题 1.网络结构和社团结构 在社交网络中,用户相当于每一个点,用户之间通过互相的关注关系构成了整个网络的结构,在这样的网络中,有的用户之间的连接较为紧密,有的用户之间的连接关系较为稀疏, ...

  2. 【图算法】社区发现算法——Fast unfolding

    [图算法]社区发现算法--Fast unfolding 1. 社区划分问题的定义: 2. 社区划分的评价标准: 3. Fast unfolding算法: 3.1 Fast Unfolding算法的基本 ...

  3. 社区发现-Fast Unfolding

    一.简介 在社区划分问题中,存在着很多的算法,如由Newman和Gievan提出的GN算法,标签传播算法(Label Propagation Algorithm, LPA),这些算法都能一定程度的解决 ...

  4. 社区发现算法 - Fast Unfolding(Louvian)算法初探

    1. 社团划分 0x1:社区是什么 在社交网络中,用户相当于每一个点,用户之间通过互相的关注关系构成了整个网络的结构,在这样的网络中,有的用户之间的连接较为紧密,有的用户之间的连接关系较为稀疏,在这样 ...

  5. Fast unfolding of communities in large networks

    接着上文,我们需要进一步了解Gephi工具计算modularity的算法.在Gephi社区中,有文档 Modularity - Gephi Wiki 说明了算法[1]. What & Why ...

  6. Fast unfolding of communities in large networks 中文翻译

    Fast unfolding of communities in large networks 中文翻译 摘要 Keywords 1 引言 2 方法 3 应用于大型网络 4 结论和讨论 引用 Blon ...

  7. python来进行社团划分

    利用python来进行社团划分,使用的是社团划分里面的GN算法. 程序代码如下 # -*- coding: utf-8 -*- """ Created on Sat Se ...

  8. 【复杂网络】社团划分结果评估指标:Q、ARI、NMI

    社团划分结果评估指标:Q.ARI.NMI 一.模块度Q(Modularity) 模块度也称模块化度量值,是目前常用的一种衡量网络社区结构强度的方法,最早由Mark NewMan提出了.模块度的定义为: ...

  9. 可视化学习:社团划分算法——标签传播算法LPA及优化

    标签传播算法 一.社团划分质量 二.标签传播算法(LPA) 三.优化算法 1.基于传播分数的标签传播算法(LPA-S) 2.基于邻居优势的标签传播算法(LPA-N) 3.基于叶子社团合并的标签传播算法 ...

最新文章

  1. 程序员Linux学到什么程度,Linux学到什么程度,才可以找到合适的工作?
  2. LiveVideoStackCon 2021北京站 9月再次启航!
  3. volatile的作用
  4. 前端学习(3128):react-hello-react之回调形式的ref
  5. mysql ignore errors_mysql的又一个让人捉摸不透的bug?
  6. 什么是ie浏览器_关于几款电脑浏览器的使用感受,你用过吗?
  7. 搞机器学习还敲什么代码
  8. extjs 网站首页table布局,秀一下
  9. Unity(TransForm)
  10. Oracle静态数据字典
  11. python实现三级菜单
  12. 代码:小波包分解与重构、小波包能量特征提取
  13. arduino 下载 https://downloads.arduino.cc/packages/package_index.json error 出错的解决方法
  14. 谷歌浏览器扩展程序XDM_如何下载和安装扩展程序?
  15. DAVE笔记--Micrium uc-Probo DashBoard调试
  16. Django使用pyjwt实现Token跨域认证登录过程实践
  17. Qt 实现 别踩白块儿。
  18. java 数组的class_Java Class isArray()方法
  19. nltk中文分句_利用NLTK进行分句分词
  20. codevs 2905 足球晋级

热门文章

  1. 智能擦窗机器人的社会意义_擦窗机器人的现状与应用分析
  2. 《物流配送中VRP问题的多目标优化方法研究》个人小结
  3. 51单片机简易交通灯控制
  4. surfacert能跑java么_Surface RT竟然能跑Linux!微软悄然封杀
  5. caxa发生文件读写异常_为什么提示caxa读取文件错误
  6. 博达网站群的入门级指南
  7. [ZJOI2007]Hide 捉迷藏(数据结构)
  8. linux:置之死地而后生,一次系统急救后的经验总结
  9. 帧同步在竞技类网络游戏中的应用
  10. 打开eclipse时没有GBK码表怎么解决