选自towardsdatascience
图(graph)近来正逐渐变成机器学习的一大核心领域,比如你可以通过预测潜在的连接来理解社交网络的结构、检测欺诈、理解汽车租赁服务的消费者行为或进行实时推荐。近日,数据科学家 Maël Fabien 在其博客上发布了涉及图论、图算法和图学习的系列文章《图论与图学习》。
主要的图算法
示意图和用例
Python 示例
import numpy as np
import random
import networkx as nx
from IPython.display import Image
import matplotlib.pyplot as plt
实时欺诈检测
实时推荐
精简法规遵从性
复杂网络的管理和监控
身份和访问管理
社交应用/功能
…
Pathfinding(寻路):根据可用性和质量等条件确定最优路径。我们也将搜索算法包含在这一类别中。这可用于确定最快路由或流量路由。
Centrality(中心性):确定网络中节点的重要性。这可用于识别社交网络中有影响力的人或识别网络中潜在的攻击目标。
Community detection(社群检测):评估群体聚类的方式。这可用于划分客户或检测欺诈等。
寻路算法是通过最小化跳(hop)的数量来寻找两个节点之间的最短路径。
搜索算法不是给出最短路径,而是根据图的相邻情况或深度来探索图。这可用于信息检索。
宽度优先搜索(BFS):首先探索每个节点的相邻节点,然后探索相邻节点的相邻节点……
深度优先搜索(DFS):会尝试尽可能地深入一条路径,如有可能便访问新的相邻节点。
最短路径计算的是一对节点之间的最短的加权(如果图有加权的话)路径。
将图中所有节点标记为未访问。创建一个所有未访问节点的集合,称为未访问集。
为每个节点分配一个暂定的距离值:将我们的初始节点的该值设置为零,将其它所有节点的该值设置为无穷。将初始起始节点设置为当前节点。
对于当前节点,考察其所有未被访问过的相邻节点并计算通过当前节点的暂定距离。比较新计算出的暂定距离与当前分配的值,配之以其中更小的值。举个例子,如果当前节点 A 标记的距离为 6,将其与相邻节点 B 连接的边的长度为 2,则通过 A 到达 B 的距离为 6+2=8。如果 B 之前被标记的距离大于 8,则将其改为 8。否则,保持其当前的值。
当我们考察完当前节点的所有未访问节点时,将当前节点标记为已访问,并将其移出未访问集。已访问节点不会再次进行检查。
如果目标节点已被标记为已访问(当规划两个特定节点之间的路由时)或未访问集中节点之间的最小暂定距离为无穷时(当规划一次完整的遍历时;当初始节点与剩余的未访问节点之间没有连接时才会出现这种情况),那么就停止操作。算法结束。
否则,选择标记有最小暂定距离的未访问节点,将其设置为新的「当前节点」,然后回到步骤 3。
# Returns shortest path between each node
nx.shortest_path(G_karate)
{0: {0: [0],
1: [0, 1],
2: [0, 2],
...
单源最短路径(Single Source Shortest Path/SSSP)是找到给定节点与图中其它所有节点之间的最短路径。
所有配对最短路径(All Pairs Shortest Path / APSP)算法是找到所有节点对之间的最短路径。
# Returns shortest path length between each node
list(nx.all_pairs_shortest_path_length(G_karate))
[(0,
{0: 0,
1: 1,
2: 1,
3: 1,
4: 1,
...
最小权重生成树(minimum spanning tree)是图(一个树)的一个子图,其用权重和最小的边连接了图中的所有节点。
from networkx.algorithms import tree
mst = 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),
...
社群检测是根据给定的质量指标将节点划分为多个分组。
计算网络中所有已有边的居间性。
移除居间性最高的边。
移除该边后,重新计算所有边的居间性。
重复步骤 2 和 3,直到不再剩余边。
from networkx.algorithms import communityk = 1
comp = community.girvan_newman(G_karate)for communities in itertools.islice(comp, k):
print(tuple(sorted(c) for c in communities))
([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])
首先为每个节点分配一个社群
交替执行接下来的两个步骤,直到收敛
创建一个带有相邻节点的新社群,以最大化模块性
创建一个新的加权的图。之前步骤的社群变成图的节点。
pip install python-louvain
import community
partition = 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)
强互连的组分(Strongly Connected Components /SCC)算法能找到有向图中的互连节点的分组。注意,在同一个分组中,每个节点都必须从任意其它节点从两个方向都到达。
弱互连的组分(Weakly Connected Components),也称为并查集(Union Find)算法,能找到有向图中的互连节点的集合,在同一个集合中,每个节点都可从任意其它节点到达。
nx.is_weakly_connected(G)
nx.is_strongly_connected(G)
nx.is_connected(G_karate)
在分层聚类(hierarchical clustering)中,我们构建聚类的层次结构。我们用树状图的形式表示聚类。
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 j
for i in range(n):
for j in range(n):
distances[i, j] = pcc_longueurs[i][1][j]
from sklearn.cluster import AgglomerativeClusteringclustering = AgglomerativeClustering(n_clusters=2,linkage='average',affinity='precomputed').fit_predict(distances)
nx.draw(G_karate, node_color = clustering)
聚类系数衡量的是两个节点倾向于聚类到一起的程度。
# List of local clustering coefficients
list(nx.clustering(G_barabasi).values())
0.13636363636363635,
0.2,
0.07602339181286549,
0.04843304843304843,
0.09,
0.055384615384615386,
0.07017543859649122,
...
# Global clustering coefficient
np.mean(list(nx.clustering(G_barabasi).values()))
0.0965577637155059
中心度(Centrality)衡量的是节点的重要程度。这并非一个明晰的定义,但如果我们想要确定重要的网页、交通网络中的瓶颈……,那这就会很有用。
nx.pagerank(G_karate, alpha=0.9)
{0: 0.09923208031303203,
1: 0.0543403155825792,
2: 0.05919704684187155,
3: 0.036612460562853694,
...
度中心度(Degree Centrality)统计的是终止于节点 i 的长度为 1 的游走的数量。
c_degree = nx.degree_centrality(G_karate)
c_degree = list(c_degree.values())
特征向量中心度(Eigenvector Centrality)是终止于节点 i 的长度为无穷的游走的数量。
c_eigenvector = nx.eigenvector_centrality(G_karate)
c_eigenvector = list(c_eigenvector.values())
接近度中心度(Closeness Centrality)检测的是可以在图中有效传播信息的节点。
c_closeness = nx.closeness_centrality(G_karate)
c_closeness = list(c_closeness.values())
居间性中心度(Betweenness Centrality)检测的是节点在图中的信息流上所具有的影响量。
σ_jk 是 j 和 k 之间的最短路径的数量
σ_jk(i) 是 j 和 k 之间的经过 i 的最短路径的数量
c_betweenness = nx.betweenness_centrality(G_karate)
c_betweenness = list(c_betweenness.values())
# Plot the centrality of the nodes
plt.figure(figsize=(18, 12))# Degree Centrality
f, 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 Centrality
plt.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 Centrality
plt.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 Centrality
plt.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)
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/
原文链接:https://towardsdatascience.com/graph-algorithms-part-2-dce0b2734a1d
本文为机器之心编译,转载请联系本公众号获得授权。
✄------------------------------------------------
加入机器之心(全职记者 / 实习生):hr@jiqizhixin.com
投稿或寻求报道:content@jiqizhixin.com
广告 & 商务合作:bd@jiqizhixin.com