社区发现算法

一.原始LPA算法

  • 引用
    https://greatpowerlaw.wordpress.com/2013/02/08/community-detection-lpa/
  • 算法原理

    标签传播算法是不重叠社区发现的经典算法,其基本思想是:将一个节点的邻居节点的标签中数量最多的标签作为该节点自身的标签。给每个节点添加标签(label)以代表它所属的社区,并通过标签的“传播”形成同一标签的“社区”结构。

    1.Label Propagation算法(LPA)最吸引人的地方,在于它的简单–核心思路的简洁,并且很容易实现。一个简单的算法意味着易于理解,并且容易在它之上做很多有针对性的改良。
    2.LPA的另一个极大的优点在于scalability。LPA非常适合用来处理large graph,因为算法的实质是 vertex-centric model,所以其实是可以在Map-Reduce上实现它。
    3.和很多基于clustering算法不同的是,LPA不需要预先给定community的数量。基于clustering的算法一般都需要预先给定些seeds,而LPA不需要任何的先验知识。这点对于处理large graph也是非常重要的,你很难知道一个千万/上亿节点的graph能够被划分成多少个community。

  • 算法计算过程

    1. 初始整个graph。对于graph中的每个node,分配一个唯一的label。一般可以考虑用node的id当成它的label id;
    2. 开始计算每个node新的label。计算的规则是,统计node周围所有邻居的label,出现次数最多的label将被设置成这个node的新label;
    3. 如果邻居中出现次数最多的label有多个,那么随机的选择其中的一个label (例如在起始计算中,因为每个node的label都是唯一的,所以每个node周围所有的label出现次数都是1,这时候相当于随机的选择一个邻居的label作为自己的label);
    4. 计算所有node之后,判断是否达到了终止条件,如果没有,回到第2步继续计算;
    5. 经过几次迭代,到达终止条件,算法完成。现在图中,具有相同label的node属于同一个community。

    在每次迭代中,计算node的label有两种方式:synchronous,asynchronous.

    synchronous: 就是在当前迭代中,是基于邻居的上一次迭代中的label来更新node的新label.
    asynchronous: node的label并不区分当前迭代和上一次迭代,永远都只使用node最新的label.

    原始paper中是推荐使用asynchronous方式的,主要原因在于synchronous可能出现label的交替振荡而无法达到稳定态,这种情况很容易在星状图中出现.

二.LPA算法(半监督)

  • 引用
    https://yq.aliyun.com/articles/69945
  • 算法原理

    1.根据LPA算法基本理论,每个节点的标签按相似度传播给相邻节点,在节点传播的每一步,每个节点根据相邻节点的标签来更新自己的标签,与该节点相似度越大,其相邻节点对其标注的影响权值越大,相似节点的标签越趋于一致,其标签就越容易传播。
    2.在标签传播过程中,保持已标注数据的标签不变,使其像一个源头把标签传向未标注数据。
    3.最终,当迭代过程结束时,相似节点的概率分布也趋于相似,可以划分到同一个类别中,从而完成标签传播过程。

    LP算法包括两大步骤:1)构造相似矩阵;2)勇敢的传播吧。

  • 算法计算过程

    首先,定义一个NxN的概率转移矩阵P:

    Pij=P(i>j)=wijnk=1wik Pij 表示从节点i转移到节点j的概率。

    • 假设有C个类和L个labeled样本,我们定义一个LxC的label矩阵 YL ,第i行表示第i个样本的标签指示向量,即如果第i个样本的类别是j,那么该行的第j个元素为1,其他为0。
    • 同样,我们也给U个unlabeled样本一个UxC的label矩阵 YU
    • 把他们合并,我们得到一个NxC的soft label矩阵F=[ YL ; YU ]。soft label的意思是,我们保留样本i属于每个类别的概率,而不是互斥性的,这个样本以概率1只属于一个类。当然了,最后确定这个样本i的类别的时候,是取max也就是概率最大的那个类作为它的类别的。
    • F里面有个 YU ,它一开始是不知道的,那最开始的值是多少?无所谓,随便设置一个值就可以了。

    简单的LP算法如下:

    1. 执行传播:F=PF
    2. 重置F中labeled样本的标签:FL=YL
    3. 重复步骤1和2直到F收敛

    ps:
    步骤1就是将矩阵P和矩阵F相乘,这一步,每个节点都将自己的label以P确定的概率传播给其他节点。如果两个节点越相似(在欧式空间中距离越近),那么对方的label就越容易被自己的label赋予,就是更容易拉帮结派。
    步骤2非常关键,因为labeled数据的label是事先确定的,它不能被带跑,所以每次传播完,它都得回归它本来的label。随着labeled数据不断的将自己的label传播出去,最后的类边界会穿越高密度区域,而停留在低密度的间隔中。相当于每个不同类别的labeled样本划分了势力范围。

三.Louvain社区发现算法

  • 引用
    http://www.cnblogs.com/fengfenggirl/p/louvain.html
  • 算法原理

    模块度(Modularity )
      模块度是评估一个社区网络划分好坏的度量方法,它的物理含义是社区内节点的连边数与随机情况下的边数只差,它的取值范围是 [−1/2,1),其定义如下:
      
       Q=12mi,j[Aijkikj2m]δ(ci,cj)
       δ(u,v)={1when u==v0 else
      
      其中, Aij 节点i和节点j之间边的权重,网络不是带权图时,所有边的权重可以看做是1; ki=jAij 表示所有与节点i相连的边的权重之和(度数); ci 表示节点i所属的社区; m=12ijAij 表示所有边的权重之和(边的数目)。
      公式中 Aijkikj2m=Aijkikj2m ,节点j连接到任意一个节点的概率是 kj2m ,现在节点i有 ki 的度数,因此在随机情况下节点i与j的边为 kikj2m .
      模块度的公式定义可以作如下简化:
     
      Q=12mi,j[Aijkikj2m]δ(ci,cj)
      =12m[i,jAijikijkj2m]δ(ci,cj)
      =12mc[Σin(Σtot)22m]
     
      其中 Σin 表示社区c内的边的权重之和, Σtot 表示与社区c内的节点相连的边的权重之和。
      上面的公式还可以进一步简化成:
     
      Q=c[Σin2m(Σtot2m)2]
      =c[ecac2]
     
       这样模块度也可以理解是社区内部边的权重减去所有与社区节点相连的边的权重和,对无向图更好理解,即社区内部边的度数减去社区内节点的总度数。
      基于模块度的社区发现算法,都是以最大化模块度Q为目标。

  • 算法计算过程

     Louvain算法的思想很简单:
    1)将图中的每个节点看成一个独立的社区,次数社区的数目与节点个数相同;
    2)对每个节点i,依次尝试把节点i分配到其每个邻居节点所在的社区,计算分配前与分配后的模块度变化 ΔQ ,并记录 ΔQ 最大的那个邻居节点,如果 maxΔQ>0 ,则把节点i分配 ΔQ 最大的那个邻居节点所在的社区,否则保持不变;
    3)重复2),直到所有节点的所属社区不再变化;
    4)对图进行压缩,将所有在同一个社区的节点压缩成一个新节点,社区内节点之间的边的权重转化为新节点的环的权重,社区间的边权重转化为新节点间的边权重;
    5)重复1)直到整个图的模块度不再发生变化。

    从流程来看,该算法能够产生层次性的社区结构,其中计算耗时较多的是最底一层的社区划分,节点按社区压缩后,将大大缩小边和节点数目,并且计算节点i分配到其邻居j的时模块度的变化只与节点i、j的社区有关,与其他社区无关,因此计算很快。在论文中,把节点i分配到邻居节点j所在的社区c时模块度变化为:

    ΔQ=[in+ki,in2m(tot+ki2m)2][in2m(tot2m)2(ki2m)2]

    其中 ki,in 是社区c内节点与节点i的边权重之和,注意对 ki,in 是对应边权重加起来再乘以2,这点在实现时很容易犯错。
    DeltaQ 分了两部分,前面部分表示把节点i加入到社区c后的模块度,后一部分是节点i作为一个独立社区和社区c的模块度,这里有一个困惑我的地方,虽然我按照这个公式实现的分群算法效果很好,但是我认为 DeltaQ 少了把节点i从其原来社区删除这一步,因为后面的划分时,节点i所在的社区可能有多个节点。
      在实现的时候模块度变化还可以简化,把上面的公式展开,很多项就抵消了,化简之和:
       ΔQ=[ki,in2mtotki2m2]

你可能感兴趣的:(图算法)