标签传播算法(LPA)

LPA简介

什么是LPA

标签传播算法(Label Propagation Algorithm,LPA),是一种基于标签传播的局部社区划分算法。LPA将Grpah中的每个节点打上唯一的标签,通过随机选择一个node作为起始节点,根据其相连节点的标签改变自己的标签,以此来对整个图进行遍历,每一次迭代,图局部标签进行更新,从而达到整个Graph的标签确定。

优点

1、逻辑简单,整个计算过程几乎为线性计算,迭代速度快;
2、无需借助其他评测,只依赖自身标签;
3、无需提前划分社区数量,完全由迭代后进行决定。

缺点

1、随机性强,首次选中的节点可能会对后续节点的确定产生影响,进而影响全局标签;
2、节点更新顺序不确定,每次迭代的结果也不确定。

计算过程

1、初始化所有节点,标属每个节点的唯一标签;
2、随机选择一个节点N,将该节点的邻居节点(X1-Xn)的标签进行统计,选择频次最多的一个标签Xi;
3、如果有多个标签频次相同,那么随机选择一个标签,将该标签赋予N;
4、重复2、3步,直到标签不再变化或者迭代次数足够。

代码实现

我们以networkx中集成的LPA算法为例,来说明每个步骤:

import networkx as nx
from networkx.algorithms.community import asyn_lpa_communities as lpa
import random

首先,导入networkx以及LPA

G = nx.karate_club_graph()

data = lpa(G,weight='weight',seed=random)
for i,v in enumerate(data):
    print(i,v)

其次,以networkx中的空手道数据为例,来运行一下

0 {0, 1, 2, 3, 7, 11, 12, 13, 17, 19, 21}
1 {10, 4}
2 {16, 5, 6}
3 {32, 33, 8, 9, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}

然后,我们可视化看一下聚类的结果:
在这里插入图片描述
如图所示,可以看出最终的数据经过LPA分成了4簇,从算法到数据是不是简单的不要了。

重点来了,源码分析

我们来剖析networkx是如何实现LPA算法的。

#定义每个节点的标签,即每个节点所对应的索引值
labels = {n: i for i, n in enumerate(G)}
#设定一个起始和终止条件
cont = True
while cont:
    cont = False
    #将图中的节点列表化
    nodes = list(G)
    #打乱列表中的数据
    seed.shuffle(nodes)
    #选择一个节点开始
    for node in nodes:
    	#如果该节点为单独节点,则不需进行打标
        if not G[node]:
            continue
        #判断是否需要依赖权重计算
        if weight is None:
        	#在非权重图下,直接计算每个标签的个数,结果为“节点标签:标签个数”
            label_freq = Counter(map(labels.get, G[node]))
        else:
        	#定义字典
            label_freq = defaultdict(float)
            #遍历每个邻居节点的属性
            for _, v, wt in G.edges(node, data=weight, default=1):
            	#获取每个节点的权重值,结果为“节点标签:每个标签累计权重之和”
                label_freq[labels[v]] += wt
		#选择频率最高或者权重最大的那个value
        max_freq = max(label_freq.values())
        #获取该值对应的标签
        best_labels = [
            label for label, freq in label_freq.items() if freq == max_freq
        ]
		#判断该节点标签是否已经被新标签覆盖
        if labels[node] not in best_labels:
        	#随机选择一个标签覆盖原来的标签
            labels[node] = seed.choice(best_labels)
            cont = True
#返回最终划分社区
yield from groups(labels).values()

整体看起来,networkx实现的算法很简洁,是根据异步更新实现的。其中,对是否加载图权重的问题分别进行实现,用起来还是非常方便了。

trick

在这里插入图片描述请大家看一看,这张图和上面那张有什么地方不一样呢?
很明显,上面图中有4种颜色,而这张图中有3种颜色,也就是说,同样的数据,同样的算法,但是结果不太一致,这是为什么?
这正是因为初始的节点选择不同,导致了不太一样的结果,那么在实际应用中,在满足使用条件的前提下,多进行几次计算,选择簇类比较少的结果,可以更好的在后面使用中,尽量避免因为簇的个数较多或者簇中数据单一,导致该簇数据不可用。
以上trick仅针对使用的例子数据,仅做参考。
好啦,以上就是我对LPA的一个简单的理解和介绍,如果大家有什么问题或者补充,请加我QQ:1143948594,随时交流!!!

附:论文地址:https://arxiv.org/pdf/0709.2938.pdf

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值