Fast Newman-FN算法以及模块度定义介绍

 一、社区的定义

     Newman第一次提出模块度定义就是在2004年发表的这篇文章“fast algorithm for community structure in networks”,第一次用量化的公式来确定社区划分。

     首先,我们来看Newman如何定义社区的:the vertices in networks are often found to cluster into tightly knit groups with a high density of within-group edges and a lower density of between -group edges。

    用大白话说就是:社区内部的边尽可能地多,但是社区之间的边尽可能地少

(一些定义):i、j指社区i和社区j;

                   n是网络中节点的数量;

                   m是网络中边的数量。一条边上连接两个节点,和明显,2m即网络中所有节点度之和

二、如何量化到模快度?

    我们先用eij表示社区i和社区j之间连接的边的数量比整个网络边的数量,eii表示社区i内部边的数量比整个网络边的数量,既然这样的话我们只要使∑ieii尽可能大就好了,但是问题又来了,最大肯定就是1咯,所有节点归为一个社区,那这样很明显就没有意义了。

    于是他有提出,网络中连接两个同种类型的边(即社区内部的边的比例eii)减去在相同结构下任意连接这两个节点边的比例的期望,于是模块度登场

               Q=∑i(eii-ai2)

 其中,ai=∑jeij  表示与社区i中节点相连的边占所有边的比例。如果社团内部边的比例不大于社团内部边随机连接的期望,那么Q=0,最大时为1。一般来说,Q值最大对应的社团结构就是网络中的社团结构

三、如何变成算法可操作性?

     意思来了,我们只要优化Q就好了,但是如何把n个节点划分多少个社区?每个社区多少个节点?作者指出有2n-1种可能,这样的话根本无法将Q推广在高于20节点以上的网络?为了减少时间复杂度,作者提出一种贪婪策略

    FN:(1)首先将网络中每个节点自定义成一个社区

           (2)计算出两两社区结合是Q的值,找到Q增加最大的或者减少最少的合并方式进行社区合并

           (3)直到所有社区合并成一个大社区时停止,找出合并过程中最大的Q是的社区划分结果

这个时候,Newman有注意到,当两个社区合并时,模块度的增量detaQ=(eji+eij-2ai*aj)=2(eij-2ai*aj)

四、代码来了

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
clear all
close all
clc
 
% load preprocess.mat
% E=e;
load('dolphin.mat');
E=A;
% E(find(E>0))=1;%建立邻接矩阵
tic;
e=E;
e(e==1)=1/sum(E(:));
a=sum(e);
n=size(A,2);
b=[1:n];
b=num2cell(b);%用来存储社团元素的变量
c={};
k=1;
while length(e)>1
      lg=length(e);
      detaQ=-(10^9)*ones(n-k+1);%△Q
      for i=1:lg-1
          for j=i+1:lg
             if e(i,j)~=0
                detaQ(i,j)=2*(e(i,j)-a(i)*a(j));%计算△Q
             end
          end
      end
   if sum(detaQ+(10^9))==0
      break
   end
% Q(k)=max(detaQ(:));%寻找△Q的最大值,并把它存储进Q(k)矩阵
%-----------------------------寻找最大△Q对应的两个社团,并将其合并,并改变e矩阵
[I,J]=find(detaQ==max(detaQ(:)));
 
     for ii=1:length(I)
         e(J(ii),:)=e(I(ii),:)+e(J(ii),:);
         e(I(ii),:)=0;
         e(:,J(ii))=e(:,I(ii))+e(:,J(ii));
         e(:,I(ii))=0;
 
% e(I,I)=e(I,I)/2;
%—————————记录△Q最大所对应的社团以及各社团中的元素
 
        b{J(ii)}=[b{I(ii)} b{J(ii)}];
        b{I(ii)}=0;
     end
 
  e(I,:)=[];
  e(:,I)=[];
  b(I)=[];
  c(k,:)=num2cell(zeros(1,n));
  c(k,1:length(b))=b;
  for kk=1:length(b)
      c2=cell2mat(c(k,kk));
      c2(c2==0)=[];
      c{k,kk}=c2;
      c2=[];
  end
a=sum(e);
k=k+1;
tmp=0;
  for jj=1:length(e)
      tmp=tmp+(e(jj,jj)-a(jj)*a(jj));
  end
Q(k)=tmp;
end
max_k=find(Q==max(Q(:)))-1;
 
ll=0;
for i=1:length(c(max_k,:))
    if sum(c{max_k,i})~=0
        ll=ll+1;
        c{max_k,i}=c{max_k,i}(c{max_k,i}~=0);
    end
end
c_newman=c(max_k,1:ll);
label=zeros(n,1);
for i=1:ll
    label(c{max_k,i}')=i;
end

 

  

 

posted @   bethansy  阅读(11070)  评论(3编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!
点击右上角即可分享
微信分享提示