论文地址

该算法用于检测网络中的社区、桥节点和离群点。它基于结构相似性度量对顶点进行聚类。该算法特点是:速度快,效率高,每个顶点只访问一次。

主要贡献是能够识别出桥节点离群点两种特殊点。

前面提到的大多数方法倾向于社区网络,这样每个社区中都有一组密集的边,而社区之间的边很少。基于模块的和归一化切割算法是典型的例子。

然而,这些算法并不区分网络中顶点的角色。有些顶点是集群的成员;有些顶点是桥接许多集群但不属于任何集群的桥节点,而有些顶点则是只与特定集群有弱关联的离群点

现有的方法,如基于模块的算法,会将这个例子分成两个集群:一个由顶点0到6组成,另一个由顶点7到13组成。它们没有隔离顶点6(一个桥节点,将其划分到在任何一个集群中都是有争议的)或顶点13(一个离群点,它只与网络有一个连接)。

**SCAN(网络结构聚类算法)**的目标是在大型网络中找到集群、桥节点和离群点。

为了实现这个目标,该算法使用顶点的邻域作为聚类标准,而不是只使用它们的直接连接。顶点按照它们共同邻域的方式分组到集群中。

这样做是很有意义的,比如当我们考虑到大型社交网络中的社区检测时,拥有很多共同好友的两个人应该聚集在同一个社区。

再次参考上图中的示例:

  1. 考虑顶点 0 和 5,它们由一条边连接。它们的邻域分别是顶点集 {0,1,4,5,6} 和 {0,1,2,3,4,5}。它们共享许多邻居,因此被合理地分组在同一个集群中。
  2. 考虑顶点 13 和顶点 9 的邻域。这两个顶点是连接的,但只有两个公共邻居,即 {9,13}。因此,它们是否应该被归为同一类是值得商榷的。
  3. 考虑顶点 6 的情况。它有很多邻居,但它们之间的联系很少。

因此通过SCAN最终目标是确定了两个集群,{0,1,2,3,4,5} 和 {7,8,9,10,11,12},并将顶点 13 作为离群点,将顶点6作为桥节点。

SCAN 算法有以下特点:

  • 通过使用顶点的结构和连接性作为聚类标准来检测集群、桥节点和离群点。理论分析和实验评估证明,SCAN 可以在非常大的网络找到有意义的集群、桥节点和离群点。
  • 速度快。它在有n个顶点和m条边的网络上的运行时间是O(m)。

节点相似度:

节点相似度定义为两个节点共同邻居的数目两个节点邻居数目的几何平均数的比值(这里的邻居均包含节点自身)。

其中 Γ(x) 表示节点 x 及其相邻节点所组成的集合。

Ε - 邻居:

节点的 ϵ-邻居定义为与其相似度不小于 ϵ 的节点所组成的集合。

核节点:

核节点是指 ϵ-邻居的数目大于 μ 的节点

直接可达:

节点 w 是核节点 v 的 ϵ-邻居,那么称从 v 直接可达 w。

可达:

节点 v 可达 w ,存在链路v1…w,链路上上一点直接可达下一点。即起始点一个个直接可达下一个节点直到终点,然后形成可达。

相连:

若核节点u可达节点v和节点w,则称节点v和节点w相连.

相连聚类:

如果一个非空子图C中的所有节点是相连的,并且C是满足可达的最大子图,那么称C是一个相连聚类。

桥节点:

与至少两个聚类相邻的孤立节点。

离群点:

只与一个聚类相邻或不与任何聚类相邻的孤立节点。

引理一:

如果 v 是一个核节点,那么从 v 可达的节点集是一个结构相连聚类。

引理二:

C 是一个结构相连聚类, p 是 C 中的一个核节点。那么 C 等于从 p 结构可达的节点集。

这两个引理可以知道找到核心节点可达的节点集就找到了一个社区。

算法流程:

  • 在开始时,所有的顶点都被标记为非分类的。扫描算法对每个顶点进行分类,要么是集群的成员,要么是非成员。
  • 对于尚未分类的每个顶点,扫描检查是否这个顶点的核心(STEP 1)。
  • 如果顶点是核心,则从这个顶点拓展一个新的集群(STEP 2.1)。否则,顶点标注为非成员(STEP 2.2)。
  • 为了找到一个新的集群,从任意核心 v 搜索所有可达顶点。由于引理2,这足以找到包含顶点 v 的完整集群。

在STEP 2.2中,会生成一个新的集群ID,该ID将分配给STEP 2.2中找到的所有顶点。

SCAN首先选择一个未被分类的核心节点v,将v设为一个社区。然后将核心节点v 的所有其 ϵ-邻居放进队列中。对于队列中的每个顶点,它计算所有直接可达的顶点,并将那些仍未分类的顶点插入队列中。重复此操作,直到队列为空。这样一个社区就找到了。然后找其它未被分类的核心节点重复以上步骤。

Python代码如下

import networkx as nx
import random
import math
import matplotlib.pyplot as pltclass SCAN:def __init__(self, G, epsilon=0.5, mu=3):self._G = Gself._epsilon = epsilonself._mu = mu# 节点的 ϵ-邻居定义为与其相似度不小于 ϵ 的节点所组成的集合def get_epsilon_neighbor(self, node):return [neighbor for neighbor in self._G.neighbors(node) ifcal_similarity(self._G, node, neighbor) >= self._epsilon]# 判断是否是核节点def is_core(self, node):# 核节点是指ϵ-邻居的数目大于 μ 的节点。return len(self.get_epsilon_neighbor(node)) >= self._mu# 获得桥节点和离群点def get_hubs_outliers(self, communities):other_nodes = set(list(self._G.nodes()))node_community = {}for i, c in enumerate(communities):for node in c:# 已经有社区的节点删除other_nodes.discard(node)# 为节点打上社区标签node_community[node] = ihubs = []outliers = []# 遍历还未被划分到社区中的节点for node in other_nodes:neighbors = self._G.neighbors(node)# 统计该节点的邻居节点所在的社区  大于1为桥节点 否则为离群点neighbor_community = set()for neighbor in neighbors:if neighbor in node_community:neighbor_community.add(node_community[neighbor])if len(neighbor_community) > 1:hubs.append(node)else:outliers.append(node)return hubs, outliersdef execute(self):# 随机访问节点visit_sequence = list(self._G.nodes())random.shuffle(visit_sequence)communities = []for node_name in visit_sequence:node = self._G.nodes[node_name]# 如果节点已经分类好 则迭代下一个节点if node.get("classified"):continue# 如果是核节点 则是一个新社区if self.is_core(node_name):  # a new communitycommunity = [node_name]communities.append(community)node["type"] = "core"node["classified"] = True# 获得该核心点的ϵ-邻居queue = self.get_epsilon_neighbor(node_name)# 首先将核心点v的所有其 ϵ-邻居放进队列中。对于队列中的每个顶点,它计算所有直接可达的顶点,并将那些仍未分类的顶点插入队列中。重复此操作,直到队列为空while len(queue) != 0:temp = queue.pop(0)# 若该ϵ-邻居没被分类 则将它标记为已分类 并添加到该社区if not self._G.nodes[temp].get("classified"):self._G.nodes[temp]["classified"] = Truecommunity.append(temp)# 如果该点不是核心节点 遍历下一个节点 否则继续(不是核心节点则说明可达的点到该点终止了)if not self.is_core(temp):continue# 如果是核心节点 获得他的ϵ-邻居 看他的ϵ-邻居是否有还未被划分的 添加到当前社区R = self.get_epsilon_neighbor(temp)for r in R:node_r = self._G.nodes[r]is_classified = node_r.get("classified")if is_classified:continuenode_r["classified"] = Truecommunity.append(r)# r是核心节点还能可达其它节点 还没观察他的ϵ-邻居  放入queue中queue.append(r)return communitiesdef cal_similarity(G, node_i, node_j):# 按照公式计算相似度# 节点相似度定义为两个节点共同邻居的数目与两个节点邻居数目的几何平均数的比值(这里的邻居均包含节点自身)s1 = set(G.neighbors(node_i))s1.add(node_i)s2 = set(G.neighbors(node_j))s2.add(node_j)return len(s1 & s2) / math.sqrt(len(s1) * len(s2))

参考输出:
community: [14, 16, 33, 37, 38, 40, 43, 50]
community: [0, 1, 2, 5, 6, 7, 9, 10, 13, 17, 19, 20, 25, 26, 27, 28, 30, 32, 41, 42, 47, 54, 56, 57, 60]
community: [15, 18, 21, 24, 29, 45, 51]
hubs: [8, 36, 44, 52, 61]
outliers: [3, 4, 11, 12, 22, 23, 31, 34, 35, 39, 46, 48, 49, 53, 55, 58, 59]

代码下载

社区发现算法——SCAN算法相关推荐

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

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

  2. 附源码|复杂网络社区发现——标签传播算法(LPA)

    本文通过Python 3.7实现了标签传播算法的两个代码(1.自己写的,2.调包实现),并通过空手道俱乐部的例子进行可视化显示. 标签传播是一种半监督机器学习算法,它将标签分配给以前未标记的数据点.在 ...

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

    1.分辨率局限 louvain算法存在的问题:分辨率局限.就是说当通过优化模块度来发现社区结构时,网络在存在一个固有的分辨率局限,导致一些规模较小但是结构显著的社区淹没在大的社区中,无法被识别到. 造 ...

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

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

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

    本文结构安排 图聚类简介 正则化割 Louvain 非负矩阵分解(NMF) 其他常见方法 图(graph):是一种由点和边集构成的结构 G = ( V , E ) G=(V,E) G=(V,E) 图聚 ...

  6. 社区发现算法SCAN(python实现)

    算法是以供水管网数据为例,后面给出了社区发现结果评价指标,模块度的计算结果.如有代码疑问,私聊即可. 注:代码本人手写,未考虑任何效率问题,只是将算法过程实现,关于算法的介绍需要自行查看. SCAN算 ...

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

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

  8. 文献记录(part66)--一种基于交叉熵的社区发现算法

    学习笔记,仅供参考,有错必纠 关键词:复杂网络:社区发现:交叉熵: 一种基于交叉熵的社区发现算法 摘要 作为复杂网络中的一个极其重要的研究领域,社区结构的搜寻和发现研究具有重要的应用价值 . 该文将信 ...

  9. 社区发现SLPA算法

    社区(community)定义:同一社区内的节点与节点之间关系紧密,而社区与社区之间的关系稀疏. 设图G=G(V,E),所谓社区发现是指在图G中确定nc(>=1)个社区C={C1,C2,..., ...

最新文章

  1. linux镜像修改密码,OpenStack 镜像修改密码方案
  2. malloc 就是返回开辟内存空间的首地址
  3. 自由自在珍珠奶茶让奶茶文化更加多元
  4. 1480. Running Sum of 1d Array 一维数组的动态和
  5. C#宿舍管理系统之用户类和用户登录类
  6. Multi Task Learning在工业界如何更胜一筹
  7. iOS开发cocoaPod的使用
  8. flashBuilder安装Subclipse与XMLBuddy插件
  9. JavaWeb项目启动时,tomcat会启动两次的原因(之一)和解决方案
  10. 事务方法调用事务方法_实现系统调用的几种方法
  11. 应用程序窗口小部件App Widgets
  12. golang下的rpc框架jsonrpc理解和使用示例
  13. 人心就像内存_-Chaz-_新浪博客
  14. http web服务器
  15. python中查找文件当前位置定位,Python是怎样定位和修改文件读写位置的?
  16. html单元格斜线分割,在网页中画单元格斜线分割
  17. vscode源代码管理不显示修改的文件夹
  18. 计算机教室报损登记簿,学校实验教学工作总结
  19. Colmap论文——《Structure-from-Motion Revisited》论文阅读笔记
  20. 07.显示系统:第005课_Vsync机制:第004节_surface使用vsync过程代码分析

热门文章

  1. HashMap如何解决哈希冲突?
  2. android 方向euler,android – 如何从旋转矢量获取欧拉角(Sensor.TYPE_ROTATION_VECTOR)
  3. 如何免费给PDF文件添加标注?
  4. 各个地图坐标转换的问题
  5. JavaScript字符串对象
  6. 3种解决安卓(android)手机锁屏密码忘记的方法!
  7. 第57期、养老院信息管理系统
  8. ubuntu安装QT5.7.1
  9. LSB算法的实现(带简单界面)
  10. java json 二维数组_安卓中使用Gjson解析二维数组