本文结构安排

  • 图聚类简介

  • 正则化割

  • Louvain

  • 非负矩阵分解(NMF)

  • 其他常见方法

  • 图(graph):是一种由点和边集构成的结构 G = ( V , E ) G=(V,E) G=(V,E)

  • 图聚类(graph clustering) : 将点划分为不同的簇,使得簇内的边尽量多,簇之间的边尽量少。也称为图划分(partitioning)社区检查(community detection)

应用Louvain算法产生的社区检测图示

Normalized cut

正则化割的基本原理是使各簇之间的割最小,但不是算其最小割,因为这会使相对孤立的边缘点“自成一团”,造成社区大小的不均衡。算法的基本过程的前半部分类似于谱聚类,先由度矩阵和邻接矩阵,计算出拉普拉斯矩阵,得到第二小到K+1小的特征向量,对其进行K-means聚类,预处理得到k’个簇。之后,计算两两簇合并之后,计算其正则化割,选择正则化割最小的两个簇合并。每次合并减小一个簇,直到减小到K个簇。

k-路划分:

(1)计算相似度矩阵W和度矩阵D

(2)计算标准化拉普拉斯矩阵 D − 1 2 ( D − W ) D − 1 2 D^{-\frac{1}{2}}(D−W)D^{-\frac{1}{2}} D−21​(D−W)D−21​

(3)从第二小的特征值开始找 k ’ k’ k’个最小的特征值对应的特征向量构造 n ⋅ k ′ n \cdot k′ n⋅k′维度的特征矩阵F

(4)对特征矩阵F按行进行标准化后,进行Kmeans聚类得到 k ’ k’ k’簇

(5)在这 k ’ k’ k’个簇中,每次选取两个簇进行合并,直到最后剩下k个簇,选取的策略是最小化Ncut时的合并组合

Louvain

Louvain算法的基本原理也是采用合并的策略,但是它合并的标准是模块度增益。首先将每个节点初始化为不同社区,计算将节点加入其邻居社区的模块度增益△Q,选择使模块度增益最大的邻居进行合并,合并后的社区看做一个新的节点,直到两两社区合并的模块度增益都不大于0,则停止合并。

Louvain算法步骤如下:

(1)初始化每个数据点为一个社区;

(2)对每个数据点,尝试加入其邻居所在的社区,计算比较加入前后的模块度增益ΔQ,选出增益最大的那个邻居社区,若其对应的增益ΔQ>0,则该数据点加入这个社区,否则不改变其原来社区划分;

(3)将得到的社区视为一个节点,社区内节点之间边权重转化为新节点环的权重,社区间的边权重转化为新节点间的边权重;

(4)重复(2)(3)步骤,直至满足收敛条件。

收敛条件可以是迭代了一定的次数,亦或是模块度不再增加。

NMF

NMF的基本原理是将原始矩阵分解得到社区指示矩阵和基矩阵,随机初始化这两个矩阵的元素,迭代更新这两个矩阵,更新规则如下:

最小化目标函数:

∣ ∣ A − U V T ∣ ∣ F 2 ||A-UV^{T}||_{F}^{2} ∣∣A−UVT∣∣F2​

停止条件是目标函数收敛,即上一个计算的目标函数值,与本次目标函数值的差小于一个设定的阈值。

而对于目标函数收敛后得到的U,我们可以根据其每行(对应每个数据点)的最大值对应的列数,得到该数据点对应的类标(即将它分配给这个社区),故而可以得到如下NMF算法的算法步骤:

(1)初始化U、V矩阵(非负)

(2)根据U、V的更新公式异步迭代更新

(3)满足终止条件后终止更新U、V

(4)找到U中每个数据点最大值对应的列数,分配其作为类标

LPA

标签传播算法(LPA)的做法比较简单:

第一步: 为所有节点指定一个唯一的标签;

第二步: 逐轮刷新所有节点的标签,直到达到收敛要求为止。对于每一轮刷新,节点标签刷新的规则如下:

对于某一个节点,考察其所有邻居节点的标签,并进行统计,将出现个数最多的那个标签赋给当前节点。当个数最多的标签不唯一时,随机选一个。

KeyCode

Normalized cut
构建相似度矩阵W和计算度矩阵D;由于有每个节点的特征向量feature vector,故而节点之间的相似性可以通过对应特征向量的余弦距离度量出来,由于数据集是.mat文件,所以我使用matlab生成相似度矩阵和高斯距离矩阵后再作为Java Code的输入。

 = zeros(length(A),length(A));
for i = 1:length(A)for j = 1:i-1W(i,j) = 1-pdist2(F(i,:),F(j,:),'cosine');W(j,i) = W(i,j);end
endpublic void calculateW(){this.W=DenseMatrix.Factory.zeros(nsamples, nsamples);for (int p=0;p<nsamples;p++){for (int q=0;q<nsamples;q++){this.W.getAsDouble(CosineSimilarity(p,q));}}
}

计算标准化拉普拉斯矩阵,由度矩阵D和相似度矩阵W可得拉普拉斯矩阵L再 D − 1 2 L D − 1 2 D^{-\frac{1}{2}}LD^{-\frac{1}{2}} D−21​LD−21​进行标准化

Matrix I = DenseMatrix.Factory.eye(this.nsamples,this.nsamples);
Matrix D = DenseMatrix.Factory.eye(this.nsamples,this.nsamples);
for (int i=0;i<this.nsamples;i++){Double wij = 0.0;for (int j=0;j<this.nsamples;j++){wij+=this.W.getAsDouble(i,j);}D.setAsDouble(wij,i,i);
}
this.L = D.minus(this.W);

构建特征矩阵;计算标准化拉普拉斯矩阵的特征值和特征向量,从第二小的特征值开始选取k′个最小的特征值对应的特征向量组成特征矩阵:

Matrix[] eigenValueDecompostion = this.L.eig();
Matrix eigenVector = eigenValueDecompostion[0];
Matrix eigenValue = eigenValueDecompostion[1];
List<Matrix> res = eigenVector.getColumnList();
List<Matrix> NCutResult=new ArrayList<>();
for (int i=1;i<this.k+1;i++){NCutResult.add(res.get(i));
}

对特征矩阵进行聚类,不断选取两个簇合并直至剩下k个簇,选取哪两个簇进行合并取决于 此时哪两个簇合并得到的Ncut值最小.

KMeans NCutkMeans = new KMeans(this.k,NCut);
NCutkMeans.clustering();

Louvain

初始化每个数据点为一个社区:

initSingletonClusters(); public void initSingletonClusters()
{int i;clustercount = nodecount;cluster = new int[nodecount];for (i= 0; i < nodecount; i++)cluster[i] = i;
}

对每个数据点,尝试加入其邻居所在的社区,计算比较加入前后的模块度增益ΔQ,记录最大的模块度增益 m a x max max和它对应的社区 m a x c l u s t e r max_cluster maxc​luster,若最大增益max>0,则将该数据点加入对应的社区 m a x c l u s t e r max_cluster maxc​luster:特别地,这里的数据点既指单个节点,也指一个社区,故统一按社区视为数据点来处理,只是单个数据点算只有一个节点的社区。

public void communityDetection(){boolean update=true;Set<Integer> cur_set = new TreeSet<>();for (int i=0;i<diGraph.getV();i++){cur_set.add(diGraph.adjList.get(i).getCluserlabel());}String current = "";String last_set = "";for (int i=0;i<diGraph.getV();i++){current+=String.valueOf(diGraph.adjList.get(i).getCluserlabel());}while (update){for (Integer i:cur_set){double bestdeltaQ=Double.NEGATIVE_INFINITY;int bestcluster = i;//initialfor (Integer j:cur_set){if (i!=j){Set<Integer> c1 = diGraph.getClusterList(i);//Cluster C1 vertex_id_setSet<Integer> c2 = diGraph.getClusterList(j);//Cluster C2 vertex_id_setif (c1.size()!=0 && c2.size()!=0) {double deltaQ = calculateDeltaQ(c1, c2, i, j);//calculate DeltaQif (deltaQ > bestdeltaQ) {bestdeltaQ = deltaQ;bestcluster = j;}}}}if (bestdeltaQ > 0){diGraph.adjList.get(i).setCluserlabel(bestcluster);//change clusterlabel}else {diGraph.adjList.get(i).setCluserlabel(i);//keep clusterlabel}diGraph.clearVisited();//clear all}last_set = current;//judge algorithm converge or notcur_set.clear();current="";for (int i=0;i<this.diGraph.getV();i++){cur_set.add(this.diGraph.adjList.get(i).getCluserlabel());}for (int i=0;i<diGraph.getV();i++){current+=String.valueOf(diGraph.adjList.get(i).getCluserlabel());}if (current.equals(last_set)){update = false;}}String filePath = "D:\\DataMining\\lab2\\"+this.name+"_Louvain.csv";FileReaderFunc.writeListToFile(filePath,CommunityLabel);
}

计算模块度增益的函数

public double calculateDeltaQ(Set<Integer> c1,Set<Integer> c2,int startlabel,int endlabel) {double m=((double) diGraph.getE());double k_i_in = diGraph.getClusterWeightIn(c1,c2,startlabel,endlabel);double sigma_in = diGraph.getIn(c2);double total = diGraph.getClusterWeightTotal(endlabel);double k_i = diGraph.getClusterWeightTotal(startlabel);double tmp1 = (sigma_in+k_i_in)/(2.0*m);double tmp2 = (total+k_i)/(2.0*m);double tmp3 = sigma_in/(2.0*m);double tmp4 = total/(2.0*m);double tmp5 = k_i/(2.0*m);double deltaQ=tmp1-tmp2*tmp2-tmp3+tmp4*tmp4+tmp5*tmp5;return deltaQ;
}

NMF
根据迭代更新公式写代码:

public void communityDetection() {Matrix fenzi = DenseMatrix.Factory.zeros(this.N,this.K);Matrix fenmu = DenseMatrix.Factory.zeros(this.N,this.K);Matrix DU = DenseMatrix.Factory.zeros(this.N,this.K);Matrix DV = DenseMatrix.Factory.zeros(this.N,this.K);Matrix Tmp = this.U.mtimes(this.V.transpose());Matrix E = this.A.minus(Tmp);double cur_error = E.norm2();double last_error = 0.0;for (int it = 0; it < this.maxiterator ; it++){fenzi = this.A.mtimes(this.V);fenmu = this.U.mtimes(this.V.transpose());fenmu = fenmu.mtimes(this.V);DU = fenzi.divide(fenmu);this.U = this.U.times(DU);fenzi = this.A.transpose().mtimes(this.U);fenmu = this.V.mtimes(this.U.transpose());fenmu = fenmu.mtimes(this.U);fenmu = fenmu.plus(this.lambda);DV = fenzi.divide(fenmu);this.V = this.V.times(DV);last_error=cur_error;Matrix Tmp1 = this.U.mtimes(this.V.transpose());Matrix E1 = this.A.minus(Tmp1);cur_error = E1.norm2();if (Math.abs(cur_error-last_error)<0.00001){break;}}
}

Experiments on Datasets

说明:相似度矩阵使用属性矩阵构造的余弦相似度
c o s X , Y = ∑ i = 1 n ( x i ∗ y i ) ∑ i = 1 n x i 2 ∗ ∑ i = 1 n y i 2 cos_{X,Y} = \frac{\sum_{i=1}^{n}(x_{i} * y_{i})}{\sqrt{\sum_{i=1}^{n}x_{i}^{2}} * \sqrt{\sum_{i=1}^{n}y_{i}^{2}}} cosX,Y​=∑i=1n​xi2​ ​∗∑i=1n​yi2​ ​∑i=1n​(xi​∗yi​)​

高斯距离矩阵使用全连接度量模式下的高斯核函数

w i j = e − c o s i n e 2 σ 2 w_{ij} = e ^{-\frac{cosine}{2\sigma^{2}}} wij​=e−2σ2cosine​

Algorithm Comparison and Hyperparameter

Normalized cut

所谓Clustering,就是说聚类,把一堆东西(合理地)分成两份或者K份。从数学上来说,
聚类的问题就相当于Graph Partition的问题,即给定一个图G = (V, E),如何把它的顶点集划分为不相交的子集,
使得这种划分最好。谱聚类算法的主要优点有:谱聚类只需要数据之间的相似度矩阵,因此对于处理稀疏数据的聚类很有效。这点传统聚类算法比如K-Means很难做到。由于使用了降维,因此在处理高维数据聚类时的复杂度比传统聚类算法好。谱聚类算法的主要缺点有:如果最终聚类的维度非常高,则由于降维的幅度不够,谱聚类的运行速度和最后的聚类效果均不好。聚类效果依赖于相似矩阵,不同的相似矩阵得到的最终聚类效果可能很不同。

Louvain

Louvain算法是一种基于多层次优化Modularity的算法,它的优点是快速、准确,是性能最好的社区发现算法之一。Modularity函数最初被用于衡量社区发现算法结果的质量,它能够刻画发现的社区的紧密程度。那么既然能刻画社区的紧密程度,也就能够被用来当作一个优化函数,即将结点加入它的某个邻居所在的社区中,如果能够提升当前社区结构的modularity。Louvain不断地遍历网络中的结点,尝试将单个结点加入能够使modularity提升最大的社区中,直到所有结点都不再变化,并且将一个个小的社区归并为一个超结点来重新构造网络,这时边的权重为两个结点内所有原始结点的边权重之和。一直迭代直至算法稳定。Louvain可以利用modularity的特性,决定是否进行合并,相比于谱聚类——无论是否合理都进行分割,Louvain的使用更加灵活,算法进行时不需要设置具体的社区个数,社区的个数由社区自己的性质决定。但是也可以在合并的过程中加入终止条件或者是别的约束,以满足固定的社区个数。

NMF

NMF(非负矩阵分解)对原始矩阵的重构误差最小化,且原始数据的统计信息也可以得到保持。NMF在处理聚类问题上有以下几个方面的优势:

  1. 非负性,由于NMF中分解得到的簇划分子矩阵具有非负性,只需要找到数据在哪个簇中的值最大就可以确定该数据的簇标签。非负矩阵分解的非负约束性使其能够清晰的指出数据点的簇标签。
  2. 易构性,根据不同的数据和目标,可以构造与之匹配的非负矩阵分解方法。只需要根据原始数据构造出原始矩阵,接着只需要加入具体的约束即可开始训练。
  3. 易于优化,因为非负矩阵分解的方法目标公式类似,所有优化的方式比较容易套用。

劣势:由于非负矩阵分解处理输入和输出全是矩阵形式的,当数据量过大时,很容易出现内存消耗过大甚至超出运行内存报错的情况,可以往这几个方面解决。采取缩减方案——多层图划分,采取划分方案——主成分分析或k均值预聚类,递增方案——随机优化非负矩阵分解方法,采取分布式并行实施方案。

LPA

标签传播算法是不重叠社区发现的经典算法,其基本思想是:将一个节点的邻居节点的标签中数量最多的标签作为该节点自身的标签。给每个节点添加标签(label)以代表它所属的社区,并通过标签的“传播”形成同一标签的“社区”结构。给每个节点添加标签(label)以代表它所属的社区,并通过标签的“传播”形成同一标签的“社区”结构。一个节点的标签取决于它邻居节点的标签:假设节点z的邻居节点有z1至zk,那么哪个社区包含z的邻居节点最多z就属于那个社区(或者说z的邻居中包含哪个社区的标签最多,z就属于哪个社区)。优点是收敛周期短,无需任何先验参数(不需事先指定社区个数和大小),算法执行过程中不需要计算任何社区指标。

时间复杂度接近线性:对顶点分配标签的复杂度为O(n),每次迭代时间为O(m),找出所有社区的复杂度为O(n+m),但迭代次数难以估计。

社区发现算法-Community Detection-NormalizeCut/Louvain/NMF/LPA相关推荐

  1. 社区发现算法原理与louvain源码解析

    前言 社区发现(community detection),或者社区切分,是一类图聚类算法,它主要作用是将图数据划分为不同的社区,社区内的节点都是连接紧密或者相似的,而社区与社区之间的节点连接则是稀疏的 ...

  2. 社区发现不得不了解的库,包含Louvain 算法、Girvan-Newman 算法等多种社区发现算法,还具有可视化功能

    熟知社区发现算法,你不能错过这个 Python 库.它涵盖 Louvain 算法.Girvan-Newman 算法等多种社区发现算法,还具有可视化功能. 网络是由一些紧密相连的节点组成的,并且根据不同 ...

  3. 社区发现算法 python_社区发现(Community Detection)算法(转)

    作者: peghoty 社区发现(Community Detection)算法用来发现网络中的社区结构,也可以看做是一种聚类算法. 以下是我的一个 PPT 报告,分享给大家. 从上述定义可以看出:社区 ...

  4. 图算法(十三):Louvain算法【适用场景:用于社团发掘、层次化聚类等场景】【基于模块度的社区发现算法,其优化目标是最大化整个社区网络的模块度】

    一.概述 Louvain算法是基于模块度的社区发现算法,该算法在效率和效果上都表现较好,并且能够发现层次性的社区结构,其优化目标是最大化整个社区网络的模块度. 适用场景:Louvain算法适用于社团发 ...

  5. 标签传播算法_复杂网络社区发现算法汇总

    社区发现 这篇文章汇总了一些常见的社区发现概念和算法,包括 Modularity Q Fast Unfolding(Louvain Algorithm) LPA SLPA KL算法 GN算法 社区: ...

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

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

  7. fastunfolding算法_社区发现算法综述—part1

    目前我能在arxiv上找到的最新的关于社区发现算法系列的综述文了. 正文从这里开始: 2.2 社区发现 现代网络在规模.多样性和复杂性上呈指数增长. 由于网络的变化,各种各样呈现出网络结构的不同类型的 ...

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

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

  9. 【Nosql-neo4j-基于社区发现算法和图分析Neo4j解读《权力的游戏》】

    <权利的游戏> 导读 导入原始数据到neo4j 人物网络分析 人物数量 概要统计 图(网络)的直径 最短路径 所有最短路径 关键节点 节点中心度(Centrality measures) ...

最新文章

  1. 决战春招!算法工程师面试问题及资料超详细合集(算法岗面经/代码实战/网课/竞赛等)...
  2. java读取excel2010文件_java如何读写excel2010
  3. php 面向过程分页,无JS,完全php面向过程,数据分页
  4. 一步一步学习OC2007(三)--定制菜单命令
  5. 深度学习中交叉熵_深度计算机视觉,用于检测高熵合金中的钽和铌碎片
  6. linux 以下命令对中正确的是什么,2016年Linux认证模拟真题及答案
  7. x264里的2pass指的是什么意思? x264源代码分析2.encode()
  8. 利用微服务构建现代应用(一)
  9. 别再说Python简单!
  10. C#Winform使用火狐firefox内核GeckoWebBrowser
  11. 计算机网络练习题-3
  12. 置信区间的临界值_在用正态分布进行置信区间估计时,临界值2.58所对应的置信水平是( )。...
  13. 无领导小组讨论题目分类
  14. 上传Excel文件进度条原理
  15. 地平线摄像头的音频调试至国际平台
  16. 通过电脑远程链接termux
  17. HTML5+CSS3小实例:酷炫的文字裂开特效
  18. 懂AI的医生一定会替代不懂AI的医生
  19. matlab已知三点求夹角,已知3点如何求其中两点对第3点的夹角
  20. app 隐私 自我评估指南_监督和改善公司隐私和安全计划的一般法律顾问指南

热门文章

  1. 高等工程热力学复习04
  2. java 分割字符串(多种方法)
  3. springboot打成jar后获取resources下文件失败, cannot be resolved to absolute file path because it does not resid
  4. 群晖服务器+微信同步,群晖服务器 云同步
  5. 在微信小游戏中实现语音互动
  6. Protocol Buffers和JSON相互转换
  7. 基于分治和DP的算法设计
  8. linux文件系统的基本特征,Linux文件系统的基本结构
  9. android开发之http协议
  10. 网站美工全能实战全解析-彭亮-专题视频课程