社区发现算法-Community Detection-NormalizeCut/Louvain/NMF/LPA

article/2025/9/27 20:30:50

本文结构安排

  • 图聚类简介

  • 正则化割

  • Louvain

  • 非负矩阵分解(NMF)

  • 其他常见方法

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

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

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

community.png

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}} D21(DW)D21

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

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

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

Ncut.png

Louvain

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

deltaQ.png

Louvain算法步骤如下:

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

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

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

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

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

NMF

nmf_pic.png

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

最小化目标函数:

∣ ∣ A − U V T ∣ ∣ F 2 ||A-UV^{T}||_{F}^{2} AUVTF2

NMF.png

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

而对于目标函数收敛后得到的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}} D21LD21进行标准化

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 maxcluster,若最大增益max>0,则将该数据点加入对应的社区 m a x c l u s t e r max_cluster maxcluster:特别地,这里的数据点既指单个节点,也指一个社区,故统一按社区视为数据点来处理,只是单个数据点算只有一个节点的社区。

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);
}

计算模块度增益的函数

deltaQ.png

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
根据迭代更新公式写代码:
NMF.png

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=1nxi2 i=1nyi2 i=1n(xiyi)

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

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

image1.png

image2.png

image3.png

image4.png

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),但迭代次数难以估计。


http://chatgpt.dhexx.cn/article/sX8YuDIk.shtml

相关文章

Louvain算法在反作弊上的应用

作者 | ANTI 一、概述 随着互联网技术的发展&#xff0c;人们享受互联网带来的红利的同时&#xff0c;也面临着黑产对整个互联网健康发展带来的危害&#xff0c;例如薅羊毛、刷单、刷流量/粉丝、品控、诈骗、快排等等&#xff0c;反作弊作为打击黑产的中坚力量&#xff0c;持…

community_louvain社群划分方法

第一、 这个方法是一个典型的EM算法。定义了一个“模块度”的量化评价指标&#xff0c;然后结合上优化方法&#xff0c;不断地优化模块度&#xff0c;最终得到社群划分的结果。 第二、模块度的定义&#xff0c;具体如下&#xff1a; 对于图中任意两个节点&#xff0c;i和j 1、…

Louvain 社团发现算法学习(我的java实现+数据用例)

为了大家方便&#xff0c;直接把数据放在github了&#xff1a; https://github.com/qq547276542/Louvain 算法介绍&#xff1a; Louvain 算法是基于模块度的社区发现算法&#xff0c;该算法在效率和效果上都表现较好&#xff0c;并且能够发现层次性的社区结构&#xff0c;其…

‘ network communites’(网络社区)(二)(louvain算法实现)

引言&#xff1a; 在&#xff08;一&#xff09;中我们学习到了什么是‘network communites’&#xff08;网络社区&#xff09;及其目标函数Q的求取&#xff0c;接下来我们要说明的是&#xff0c;我们要通过怎样的算法来实现将你的网络分成若干个集群。 一&#xff1a;louva…

neo4j实现Louvain算法

文章目录 例子一&#xff1a;创建一个属性图&#xff08;无权&#xff09;一、属性图如下二、实现算法1.stream模式执行Louvain算法&#xff08;匿名图&#xff09;2.结果如下 总结一&#xff1a;例子二&#xff1a;创建一个属性图&#xff08;有权&#xff09;一、属性图如下二…

社区发现系列03-Louvain算法分辨率

1、分辨率局限 louvain算法存在的问题&#xff1a;分辨率局限。就是说当通过优化模块度来发现社区结构时&#xff0c;网络在存在一个固有的分辨率局限&#xff0c;导致一些规模较小但是结构显著的社区淹没在大的社区中&#xff0c;无法被识别到。 造成这个问题的根本原因是模块…

(Leiden)From Louvain to Leiden:guaranteeing well-connected communities

Leiden算法 论文地址 Leiden算法是近几年的SOTA算法之一。 Louvain 算法有一个主要的缺陷&#xff1a;可能会产生任意的连接性不好的社区(甚至不连通)。为了解决这个问题&#xff0c;作者引入了Leiden算法。证明了该算法产生的社区保证是连通的。此外证明了当Leiden算法迭代应…

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

熟知社区发现算法&#xff0c;你不能错过这个 Python 库。它涵盖 Louvain 算法、Girvan-Newman 算法等多种社区发现算法&#xff0c;还具有可视化功能。 网络是由一些紧密相连的节点组成的&#xff0c;并且根据不同节点之间连接的紧密程度&#xff0c;网络也可视为由不同簇组成…

【积】有向图中的louvain社区检测(二)

有向图中的louvain社区检测 请学着自己长大&#xff0c;参考连接《无向louvain社团算法》 无向到有向的修改真的很简单。如果你连这个都做不到&#xff0c;建议不要用了。每个算法与数据匹配的时候&#xff0c;都会对数据或者算法小修。如果你连小修都做不到的话&#xff0c;…

Louvain算法实现

谢谢平台提供-http://bjbsair.com/2020-04-13/tech-info/65263.html 社区查找找的算法 Louvain是一种无监督算法&#xff08;执行前不需要输入社区数量或社区大小&#xff09;&#xff0c;分为两个阶段&#xff1a;模块化优化和社区聚集[1]。 第一步完成后&#xff0c;接下来…

Louvain 算法原理 及设计实现

模块度: Louvain算法是一种基于图数据的社区发现算法。原始论文为:《Fast unfolding of communities in large networks》。 算法的优化目标为最大化整个数据的模块度,模块度的计算如下: 其中m为图中边的总数量,k_i表示所有指向节点i的连边权重之和,k_j同理。A_{i,j} 表…

Louvain算法介绍

Louvain算法 一种基于模块度的图算法模型&#xff0c;与普通的基于模块度和模块度增益不同的是&#xff0c;该算法速度很快&#xff0c;而且对一些点多边少的图&#xff0c;进行聚类效果特别明显。 算法流程&#xff1a; 1、初始时将每个顶点当作一个社区&#xff0c;社区个数与…

Python社区发现—Louvain—networkx和community

社区 如果一张图是对一片区域的描述的话&#xff0c;将这张图划分为很多个子图。当子图之内满足关联性尽可能大&#xff0c;而子图之间关联性尽可能低时&#xff0c;这样的子图可以称之为一个社区。 社区发现算法 社区发现算法有很多&#xff0c;例如LPA&#xff0c;HANP&am…

关于在networkx中使用louvain算法报错的问题

module ‘networkx.algorithms.community’ has no attribute ‘louvain_communities’ Networkx是复杂网络科学中常用的python包&#xff0c;louvain也是常用的社团发现算法之一。在networkx的文档中也有描述。louvain_communities — NetworkX 2.8.5 documentationhttps://n…

【知识图谱】Louvain、LPA等5类经典社区发现算法 Python 实战

一、社区发现概述 根据图论&#xff0c;加权网络表示为&#x1d43a;(&#x1d449;,&#x1d438;,&#x1d44a;)&#xff0c;未加权网络表示为&#x1d43a;(&#x1d449;,&#x1d438;)&#xff0c;其中&#x1d449;和&#x1d438;表示节点和边的集合&#xff0c;&…

社区发现算法之——Louvain

1、什么是社区 如果一张图是对一片区域的描述的话&#xff0c;我们将这张图划分为很多个子图。当子图之内满足关联性尽可能大&#xff0c;而子图之间关联性尽可能低时&#xff0c;这样的子图我们可以称之为一个社区。 2、社区发现算法及评价标准 社区发现算法有很多&#xf…

python-louvain

安装 louvain当前最新版本&#xff1a;0.14 pip install python-louvain由于是处理社区的数据&#xff0c;这里还是安装networkx pip install networkx使用 不妨来运行下一个案例&#xff1a; import community as community_louvain import matplotlib.cm as cm import m…

louvain算法

简介 louvain算法由比利时鲁汶大学的 Vincent D.Blondel 等人于 2008 年提出&#xff0c;因其能以较高的效率计算出令人满意的社区识别结果&#xff0c;是近年来最多被提及和使用的社区识别算法。 Louvain算法是一种基于模块度(模块度越大则表明社区划分效果越好。Q值的…

社区发现算法——Louvain 算法

Louvain 算法 原始论文为&#xff1a;《Fast unfolding of communities in large networks》。 所以又被称为Fast unfolding算法。 Louvain算法是一种基于模块度的社区发现算法。其基本思想是网络中节点尝试遍历所有邻居的社区标签&#xff0c;并选择最大化模块度增量的社区…

Win10系统导入证书私钥

一、Win10系统导入证书私钥 二、直接点击“下一步”即可 三、输入私钥密码&#xff0c;“导入选项”按下图所示选择&#xff0c;点击“下一步” 四、默认选择“自动选择证书存储”&#xff0c;点击“下一步” 五、点击“完成”&#xff0c;弹出“导入成功”窗户&#xff0c;则私…