百摩网
当前位置: 首页 生活百科

图论的算法有哪些(图论与图学习二)

时间:2023-08-10 作者: 小编 阅读量: 1 栏目名: 生活百科

图论与图学习二选自towardsdatascience作者:MaëlFabien机器之心编译参与:熊猫图(graph)近来正逐渐变成机器学习的一大核心领域,比如你可以通过预测潜在的连接来理解社交网络的结构、检测欺诈。

选自towardsdatascience

作者:Maël Fabien

机器之心编译

参与:熊猫

图(graph)近来正逐渐变成机器学习的一大核心领域,比如你可以通过预测潜在的连接来理解社交网络的结构、检测欺诈、理解汽车租赁服务的消费者行为或进行实时推荐。近日,数据科学家 Maël Fabien 在其博客上发布了涉及图论、图算法和图学习的系列文章《图论与图学习》。

本文是其中第二篇,介绍了图算法。更多文章和对应代码可在github访问:maelfabien/Machine_Learning_Tutorials

本文涵盖以下主题:

  • 主要的图算法
  • 示意图和用例
  • Python 示例

首先进行一些准备工作,打开 Jupyter Notebook,导入以下软件包:

import numpy as npimport randomimport networkx as nxfrom IPython.display import Imageimport matplotlib.pyplot as plt

后文会使用 networkx 最新的 2.0 版本。networkx 是一个用于复杂网络的结构、动态和功能的创建、操作和研究的 Python 软件包。

我会尽量以实用为目标,努力阐释每个概念。

前一篇文章介绍了图的主要种类以及描述一个图的基本特性。现在我们更加详细地介绍图分析/算法以及分析图的不同方式。

为了理解上下文,这里给出一些图算法的用例:

  • 实时欺诈检测
  • 实时推荐
  • 精简法规遵从性
  • 复杂网络的管理和监控
  • 身份和访问管理
  • 社交应用/功能

目前大多数框架(比如 Python 的 networkx 或 Neo4J)支持的图算法类别主要有三个:

  • Pathfinding(寻路):根据可用性和质量等条件确定最优路径。我们也将搜索算法包含在这一类别中。这可用于确定最快路由或流量路由。
  • Centrality(中心性):确定网络中节点的重要性。这可用于识别社交网络中有影响力的人或识别网络中潜在的攻击目标。
  • Community detection(社群检测):评估群体聚类的方式。这可用于划分客户或检测欺诈等。

我们将在第三篇文章中介绍图中的机器学习和图学习。

networkx 中的所有算法都可在这里找到:https://networkx.github.io/documentation/stable/reference/algorithms/index.html

我们只会介绍 networkx 中实现的最常见的基本算法。

一 寻路和图搜索算法

  • 寻路算法是通过最小化跳(hop)的数量来寻找两个节点之间的最短路径。
  • 搜索算法不是给出最短路径,而是根据图的相邻情况或深度来探索图。这可用于信息检索。

1. 搜索算法

图搜索算法主要有两种:

  • 宽度优先搜索(BFS):首先探索每个节点的相邻节点,然后探索相邻节点的相邻节点……
  • 深度优先搜索(DFS):会尝试尽可能地深入一条路径,如有可能便访问新的相邻节点。

搜索算法

2. 寻路算法

a. 最短路径

最短路径计算的是一对节点之间的最短的加权(如果图有加权的话)路径。

这可用于确定最优的驾驶方向或社交网络上两个人之间的分离程度。

计算图中的最短路径的方法有很多,包括 Dijkstra 算法,这是 networkx 中的默认算法。

根据维基百科,该算法的伪代码如下:

  • 将图中所有节点标记为未访问。创建一个所有未访问节点的集合,称为未访问集。
  • 为每个节点分配一个暂定的距离值:将我们的初始节点的该值设置为零,将其它所有节点的该值设置为无穷。将初始起始节点设置为当前节点。
  • 对于当前节点,考察其所有未被访问过的相邻节点并计算通过当前节点的暂定距离。比较新计算出的暂定距离与当前分配的值,配之以其中更小的值。举个例子,如果当前节点 A 标记的距离为 6,将其与相邻节点 B 连接的边的长度为 2,则通过 A 到达 B 的距离为 6 2=8。如果 B 之前被标记的距离大于 8,则将其改为 8。否则,保持其当前的值。
  • 当我们考察完当前节点的所有未访问节点时,将当前节点标记为已访问,并将其移出未访问集。已访问节点不会再次进行检查。
  • 如果目标节点已被标记为已访问(当规划两个特定节点之间的路由时)或未访问集中节点之间的最小暂定距离为无穷时(当规划一次完整的遍历时;当初始节点与剩余的未访问节点之间没有连接时才会出现这种情况),那么就停止操作。算法结束。
  • 否则,选择标记有最小暂定距离的未访问节点,将其设置为新的「当前节点」,然后回到步骤 3。

更多有关最短路径问题的介绍请参阅:https://en.wikipedia.org/wiki/Shortest_path_problem

维基百科上 Dijkstra 算法示意图

该算法的 Python 实现简单直接:

# Returns shortest path between each nodenx.shortest_path(G_karate)

这会返回图中每个节点之间的最小路径的列表:

{0: {0: [0], 1: [0, 1], 2: [0, 2], ...

b. 单源最短路径

单源最短路径(Single Source Shortest Path/SSSP)是找到给定节点与图中其它所有节点之间的最短路径。

这常用于 IP 网络的路由协议。

c. 所有配对最短路径

所有配对最短路径(All Pairs Shortest Path / APSP)算法是找到所有节点对之间的最短路径。

尽管能够提供相近的结果,但这比为每个节点对调用单源最短路径算法更快。该算法通常可用于确定交通网格的不同分区的流量负载。

# Returns shortest path length between each nodelist(nx.all_pairs_shortest_path_length(G_karate))

这会返回:

[(0, {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, ...

d. 最小权重生成树

最小权重生成树(minimum spanning tree)是图(一个树)的一个子图,其用权重和最小的边连接了图中的所有节点。

最小生成树应该用于无向图。

from networkx.algorithms import treemst = tree.minimum_spanning_edges(G_karate, algorithm='prim', data=False)edgelist = list(mst)sorted(edgelist)

这会返回:

[(0, 1),(0, 2),(0, 3),(0, 4),(0, 5),(0, 6),...

二 社群检测

社群检测是根据给定的质量指标将节点划分为多个分组。

这通常可用于识别社交社群、客户行为或网页主题。

社区是指一组相连节点的集合。但是,目前关于社群还没有广泛公认的定义,只是社群内的节点应该要密集地相连。

社群

Girvan Newman 算法是一个用于发现社群的常用算法。其通过逐步移除网络内的边来定义社区。我们将居间性称为「边居间性(edge betweenness)」。这是一个正比于穿过该边的节点对之间最短路径的数量的值。

该算法的步骤如下:

  • 计算网络中所有已有边的居间性。
  • 移除居间性最高的边。
  • 移除该边后,重新计算所有边的居间性。
  • 重复步骤 2 和 3,直到不再剩余边。

你可以通过 Python 使用以下代码实现它:

from networkx.algorithms import communityk = 1comp = community.girvan_newman(G_karate)for communities in itertools.islice(comp, k): print(tuple(sorted(c) for c in communities))

这会得到一个属于每个社群的节点的列表(k=1 的意思是我们期望得到 2 个社群):

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

如上给出的那样,这个方法实在没法扩展。由于这个原因,Louvain 等方法已被开发出来。但是,如果要运行大规模的图,这些方法需要很长的时间。

3. Louvain 模块性

在定义 Louvain 方法之前,需要介绍一下模块性(modularity)的概念。模块性是一个度量,衡量的是分组被划分为聚类的程度:

模块性

Louvain 方法的伪代码如下:

  • 首先为每个节点分配一个社群
  • 交替执行接下来的两个步骤,直到收敛
  • 创建一个带有相邻节点的新社群,以最大化模块性
  • 创建一个新的加权的图。之前步骤的社群变成图的节点。

这个现在可能看起来有些让人迷惑。事实上,我们现在唯一做的事情是将最近的节点划分为分组,以便我们优化模块性指标。

Louvain 方法

注意,Louvain 方法没有理论上的保证,但实践效果很好。Louvain 方法是 networkx 的一个子项目,参阅:https://python-louvain.readthedocs.io/en/latest/

首先,安装软件包:

pip install python-louvain

然后,计算最佳的划分方式(基于 Louvain 方法):

import communitypartition = community.best_partition(G_karate)pos = nx.spring_layout(G_karate)plt.figure(figsize=(8, 8))plt.axis('off')nx.draw_networkx_nodes(G_karate, pos, node_size=600, cmap=plt.cm.RdYlBu, node_color=list(partition.values()))nx.draw_networkx_edges(G_karate, pos, alpha=0.3)plt.show(G_karate)

使用 Louvain 对空手道图执行的最佳划分

4. 强互连的组分

强互连的组分(Strongly Connected Components /SCC)算法能找到有向图中的互连节点的分组。注意,在同一个分组中,每个节点都必须从任意其它节点从两个方向都到达。

这通常用在图分析过程的早期阶段,能让我们了解图构建的方式。举个例子,这能让我们探索财务报表数据,了解谁拥有什么公司的股份。

5. 弱互连的组分(并查集)

弱互连的组分(Weakly Connected Components),也称为并查集(Union Find)算法,能找到有向图中的互连节点的集合,在同一个集合中,每个节点都可从任意其它节点到达。

这只需要节点对之间在一个方向上存在一条路径即可,而 SCC 则需要两个方向都存在路径。和 SCC 一样,并查集通常用在分析的早期阶段,以理解图的结构。

并查集是一个预处理步骤,为了理解图的结构,在任何算法之前都是必需的。

我们可以使用下面的方法测试相连的有向图:

nx.is_weakly_connected(G)nx.is_strongly_connected(G)

或使用下面的方法测试无向图:

nx.is_connected(G_karate)

这会返回一个布尔值。

一定要看看 networkx 文档中有关连接性实现的问题:https://networkx.github.io/documentation/stable/reference/algorithms/component.html

6. 分层聚类

在分层聚类(hierarchical clustering)中,我们构建聚类的层次结构。我们用树状图的形式表示聚类。

树状图

其思想是以不同的规模分析社群结构。我们通常自下而上构建树状图。我们从每个节点一个聚类开始,然后合并两个「最近」的节点。

但我们如何衡量聚类是否相近呢?我们使用相似度距离。令 d(i,j) 为 i 和 j 之间的最短路径的长度。

相似度距离

要得到最大连接,在每个步骤,被最短距离分开的两个聚类被组合到一起。相似度距离可用以下示意图阐释:

连接方式

回到我们的空手道示例。在应用分层聚类之前,我们需要定义每个节点之间的距离矩阵。

pcc_longueurs=list(nx.all_pairs_shortest_path_length(G_karate))distances=np.zeros((n,n))# distances[i, j] is the length of the shortest path between i and jfor i in range(n): for j in range(n): distances[i, j] = pcc_longueurs[i][1][j]

现在,我们将使用 sklearn 的 AgglomerativeClustering 函数来确定分层聚类。

from sklearn.cluster import AgglomerativeClusteringclustering = AgglomerativeClustering(n_clusters=2,linkage='average',affinity='precomputed').fit_predict(distances)

最后,根据聚类结果,用不同颜色绘出所得到的图:

nx.draw(G_karate, node_color = clustering)

分层聚类

7. 聚类系数

聚类系数衡量的是两个节点倾向于聚类到一起的程度。

局部聚类系数是以节点 i 为中心的三角形的数量与以节点 i 为中心的三节点的数量的比。某种程度而言,这衡量的是节点 i 与其相邻节点接近完备图(complete graph)的程度。

聚类系数

我通过以下图演示了聚类系数的计算:

聚类系数

全局聚类系数衡量的是图中三角形(局部聚类)的密度:

全局聚类系数

上面的图的全局聚类系数为:

对于 Erdos-Rényi 随机图,E[Clustering Coefficient]=E[Ci]=p,其中 p 是前一篇文章中定义的概率。

对于 Baràbasi-Albert 随机图,全局聚类系数根据节点的数量遵循幂律。度为 k 的节点的平均聚类系数正比于 k 的倒数:

度较低的节点连接的是它们社群中的其它节点。度较高的节点连接的是其它社群的节点。

对于一个给定的图,在 networkx 中,聚类系数很容易算出。首先,我们来计算局部聚类系数:

# List of local clustering coefficientslist(nx.clustering(G_barabasi).values())

这会得到类似下面的结果:

0.13636363636363635,0.2,0.07602339181286549,0.04843304843304843,0.09,0.055384615384615386,0.07017543859649122,...

然后平均这些结果,得到该图的全局聚类稀疏:

# Global clustering coefficientnp.mean(list(nx.clustering(G_barabasi).values()))

这会得到:

0.0965577637155059

三 中心度算法

中心度(Centrality)衡量的是节点的重要程度。这并非一个明晰的定义,但如果我们想要确定重要的网页、交通网络中的瓶颈……,那这就会很有用。

游走(walk)是可以多次经过同一个节点的路径。根据所考虑的游走类型和统计它们的方式,中心度度量也会各有不同。

1. PageRank 算法

PageRank 是根据所连接的相邻节点,然后再根据它们各自的相邻节点估计当前节点的重要性。

尽管是谷歌让这种算法流行起来的,但这种方法能够用于检测任何网络中的高影响力节点。比如可用在社交网络上进行推荐。

PageRank 要么是通过在相邻节点上迭代地分配节点的秩(原本是基于度)来计算,要么是通过随机遍历图并统计每次游走期间到达每个节点的频率来计算。

Neo4J 对 PageRank 算法的总结

PageRank 通常是在有向图上计算,但也可通过将有向图中的每条边转换成两条边而在无向图上执行。

举个例子,空手道图的 PageRank 可以这样获得:

nx.pagerank(G_karate, alpha=0.9)

其中 alpha 是阻尼参数(默认为 0.85)。这应该能返回一个排名列表:

{0: 0.09923208031303203, 1: 0.0543403155825792, 2: 0.05919704684187155, 3: 0.036612460562853694,...

2. 度中心度

度中心度(Degree Centrality)统计的是终止于节点 i 的长度为 1 的游走的数量。

这能够衡量传入和传出关系。这能通过 C(Xi)=di 给出。度中心度可用于识别社交网络中最有影响力的人。

c_degree = nx.degree_centrality(G_karate)c_degree = list(c_degree.values())

3. 特征向量中心度

特征向量中心度(Eigenvector Centrality)是终止于节点 i 的长度为无穷的游走的数量。

这能让有很好连接相邻节点的节点有更高的重要度。

特征向量中心度

c_eigenvector = nx.eigenvector_centrality(G_karate)c_eigenvector = list(c_eigenvector.values())

4. 接近度中心度

接近度中心度(Closeness Centrality)检测的是可以在图中有效传播信息的节点。

这可用于识别假新闻账户或恐怖分子,以便隔离能向图中其它部分传播信息的个体。

接近度中心度反比于到其它节点的最短路径长度的总和。

c_closeness = nx.closeness_centrality(G_karate)c_closeness = list(c_closeness.values())

5. 居间性中心度

居间性中心度(Betweenness Centrality)检测的是节点在图中的信息流上所具有的影响量。

这通常可用于发现用作从图的一部分到另一部分的桥的节点,比如用在电信网络的数据包传递处理器或假新闻传播分析中。

其中:

  • σ_jk 是 j 和 k 之间的最短路径的数量
  • σ_jk(i) 是 j 和 k 之间的经过 i 的最短路径的数量

居间性中心度衡量的是一个节点用作两个节点之间的桥的次数,比如:

中心度度量

c_betweenness = nx.betweenness_centrality(G_karate)c_betweenness = list(c_betweenness.values())

Python 中实现依赖于 networkx 的内置函数:

# Plot the centrality of the nodesplt.figure(figsize=(18, 12))# Degree Centralityf, axarr = plt.subplots(2, 2, num=1)plt.sca(axarr[0,0])nx.draw(G_karate, cmap = plt.get_cmap('inferno'), node_color = c_degree, node_size=300, pos=pos, with_labels=True)axarr[0,0].set_title('Degree Centrality', size=16)# Eigenvalue Centralityplt.sca(axarr[0,1])nx.draw(G_karate, cmap = plt.get_cmap('inferno'), node_color = c_eigenvector, node_size=300, pos=pos, with_labels=True)axarr[0,1].set_title('Eigenvalue Centrality', size=16)# Proximity Centralityplt.sca(axarr[1,0])nx.draw(G_karate, cmap = plt.get_cmap('inferno'), node_color = c_closeness, node_size=300, pos=pos, with_labels=True)axarr[1,0].set_title('Proximity Centrality', size=16)# Betweenness Centralityplt.sca(axarr[1,1])nx.draw(G_karate, cmap = plt.get_cmap('inferno'), node_color = c_betweenness, node_size=300, pos=pos, with_labels=True)axarr[1,1].set_title('Betweenness Centrality', size=16)

不同的中心度度量

可以观察到,不同的中心度度量关注的节点也不同。比如,居间性中心度得到的结果与其它方法的结果非常不同,因为它们衡量的不是同一个指标。

四 总结

现在我们已经介绍了图的基础知识、图的主要类型、不同的图算法和它们使用 networkx 的 Python 实现。

下一篇文章我们将介绍图学习,这能提供预测图中节点和边的方法,从而处理缺失值或预测新的关系。

扩展阅读:

  • Neo4j 的图算法全面指南,Mark Needham & Amy E. Hodler:https://go.neo4j.com/rs/710-RRC-335/images/Comprehensive-Guide-to-Graph-Algorithms-in-Neo4j-ebook-EN-US.pdf
  • Networkx 文档:https://networkx.github.io/documentation/stable/
,
    推荐阅读
  • 拉网捕鱼用什么方法最好(捕鱼拉网怎么拉)

    拉网捕鱼用什么方法最好采用大网目网具拉网:所用网具根据起捕鱼的规格确定,未达上市规格的鱼类基本从网目中过滤出去,不会上网,这样就缩短了操作时间,避免了缺氧情况的发生。这种方法对于鱼体受伤同样是不可避免的,特别是介于鱼种与成鱼之间的青鱼、草鱼往往容易出现挂网的情况,这些挂网鱼一般都是鳃部受伤,基本不能成活,勉强销售的经济价值也极差。

  • 做梦梦到考试(睡觉的时候梦见考试)

    做梦梦到考试求学者得此梦,乃是能力过人,文科成绩更胜一筹,多有作为,把握机遇者,学业可名列前茅。在外求财者梦见去考试,往东走吉利,往西走不吉利,与属鸡之人,属蛇之人共同求财,财运可有所作为,乃是好运之预兆。单身男人梦见去考试,贵人运多,求财者不可与他人间争执,顺其自然,生活可得改善。老年人梦之,五行属木,家庭纷争不断,家人关系不和,则得此梦多有不宁之事,郁结于心,发之于梦。

  • 第二次违章提醒软件(自以为有了免罚神器)

    第二次违章提醒软件近日执勤中,唐山市交警六大队民警发现一辆白色轿车未悬挂号牌,且行驶路线异常,遂立即上前将其拦下。通过观察,细心的民警发现该车前后方均装有能够让车牌快拆、快装的车牌架,并在车辆后备箱的角落里翻出了一副车牌,通过查询比对车架号,证实这副号牌正是该车车牌。民警现场演示了一遍“快拆”车牌,安上再拆下只用几秒的时间。随后,民警对白色轿车驾驶员作出了罚款200元,驾驶证记12分的处罚。

  • 自制果酒的危害(会对人体有什么不好的影响)

    在自制果酒的过程中需要选择新鲜的葡萄,将外皮的农药以及细菌去除掉,自然发酵过程中一定要密封好,不能让灰尘以及细菌进入,若是没有专业的酿制果酒的知识,建议不要随便酿制,避免饮用后对人体有害。

  • 做元宵的制作步骤是什么(做元宵的制作步骤)

    做元宵的制作步骤是什么?以下内容大家不妨参考一二希望能帮到您!做元宵的制作步骤是什么准备好适量糯米粉备用。将蜂蜜加在白糖中,搅拌均匀,制成蜜馅。将糯米粉用手揉匀。取揉好的小糯米团,放在手中,用手压扁,摊在手中。将糯米团用双手搓成汤圆。水烧开后,将元宵放入锅中。煮大约十五分钟,待元宵煮熟。将元宵盛起来,就可以享用了,软糯香甜,好吃极了。

  • 鲜卑契丹蒙古(鲜卑柔然蒙古)

    另一位便是建立后燕的慕容垂,襄邑之战,斩杀桓温3万。慕容恪西秦为乞伏部所建,而南凉为出自拓跋鲜卑的秃发鲜卑建立。最为牛逼的当属拓跋部建立的北魏,统一北方,统治长达150年。东胡,历史学家认为就是居住在匈奴东边的胡人。所以说东胡是对居住在长满柳树的河边的族群,在辽河上游有柳河,所以,很有可能是居住在柳河流域的族群,被称为东胡。东胡包括两个语族,蒙古语族和通古斯语族,现代的鄂温克族就是通古斯语族。

  • 早八人文案(早八人文案有哪些)

    早八人文案早八人文案特色:前两天网上刮起了一阵早安打工人的风,现在又来了一个早八人。其实呢,这个早八人就是由打工人演变来的,也是一个升级的说法吗。昨天才学会打工人这个词,今天就又开始流行“早八人”。他们每天起床的第一件事情就是空气挥一拳,早安早八人也火了。

  • 苏州科技大学考研教育学科目(苏州科技大学22教育学考研复试线及录取解读)

    苏州科技大学教育学院,成立于2018年12月,其历史可追溯到1980年成立的原苏州铁道师范学院教育教研室。2018年12月,学校再次进行教学单位调整,成立了教育学院。苏州科技大学22年教育硕士计划统招65人。

  • 切牛肉的正确方法(牛肉的做法)

    以下内容希望对你有帮助!切牛肉的正确方法首先把牛肉洗干净。然后,看清牛肉肌肉纹理的走向。切片后的牛肉,加入淀粉,这一步是锁住牛肉的水分,这样的牛肉无论是炒还是炖,都很嫩。加上点啤酒,去腥增鲜。这样就可以了,这样做出来的牛肉就特别鲜嫩了。

  • 抖音为什么涨不了粉了(抖音迟迟不爆粉)

    截至2019年1月底,已经突破30万。账号“食堂夜话”,截至2019年3月25日仅仅发布了50个视频,粉丝量竟然高达1566.5万,平均每个视频的点费数量超过100万。所以,作品的好坏,让粉丝去评价,粉丝的喜好才是作品最好的检验标准。有一个网红叫作“陆超”,每天发布的视频数量高达几十个,截至2019年3月25日,总作品数量高达6101个。