第二章 图理论基础 本章包含图的背景、图的定义、图的性质、图的连接表示、图的类型等,同时我们会学习使用 NetworkX 作为工具来学习和可视化基本的图。 关于 NetworkX 更多详细的使用,可以参考其官方文档:https://networkx.github.io/ 2.1 图的背景:柯尼斯堡七桥问题 柯尼斯堡七桥问题(德语:Königsberger Brückenproblem;英语:Seven Bridges of Königsberg)是图论中的著名问题。这个问题是基于一个现实生活中的事例:当时东普鲁士柯尼斯堡(今日俄罗斯加里宁格勒),市区跨普列戈利亚河两岸,河中心有两个小岛。小岛与河的两岸有七条桥连接。在所有桥都只能走一遍的前提下,如何才能把这个地方所有的桥都走遍?
本章包含图的背景、图的定义、图的性质、图的连接表示、图的类型等,同时我们会学习使用 NetworkX 作为工具来学习和可视化基本的图。
关于 NetworkX 更多详细的使用,可以参考其官方文档:https://networkx.github.io/
# 导入 networkx 包 import networkx as nx import matplotlib.pyplot as plt %matplotlib inline
柯尼斯堡七桥问题(德语:Königsberger Brückenproblem;英语:Seven Bridges of Königsberg)是图论中的著名问题。这个问题是基于一个现实生活中的事例:当时东普鲁士柯尼斯堡(今日俄罗斯加里宁格勒),市区跨普列戈利亚河两岸,河中心有两个小岛。小岛与河的两岸有七条桥连接。在所有桥都只能走一遍的前提下,如何才能把这个地方所有的桥都走遍?
莱昂哈德·欧拉在1735年提出,并没有方法能圆满解决这个问题,他更在第二年发表在论文《柯尼斯堡的七桥》中,证明符合条件的走法并不存在,也顺带提出和解决了一笔画问题。这篇论文在圣彼得堡科学院发表,成为图论史上第一篇重要文献。
欧拉把实际的抽象问题简化为平面上的点与线组合,每一座桥视为一条线,桥所连接的地区视为点。这样若从某点出发后最后再回到这点,则这一点的线数必须是偶数,这样的点称为偶顶点。相对的,连有奇数条线的点称为奇顶点。欧拉论述了,由于柯尼斯堡七桥问题中存在4个奇顶点,它无法实现符合题意的遍历。
柯尼斯堡七桥问题及其抽象化:
欧拉把问题的实质归于一笔画问题,即判断一个图是否能够遍历完所有的边而没有重复,而柯尼斯堡七桥问题则是一笔画问题的一个具体情境。欧拉最后给出任意一种河──桥图能否全部走一次的判定法则,从而解决了“一笔画问题”。对于一个给定的连通图,如果存在超过两个的奇顶点,那么满足要求的路线便不存在了,且有n个奇顶点的图至少需要 {\displaystyle \lceil {\frac {n}{2}}\rceil } 笔画出。如果只有两个奇顶点,则可从其中任何一地出发完成一笔画。若所有点均为偶顶点,则从任何一点出发,所求的路线都能实现,他还说明了怎样快速找到所要求的路线。
不少数学家都尝试去解析这类事例。而这些解析,最后发展成为了数学中的图论。
下面,我们通过 NetworkX 创建一个简单的图。
# 创建一个图 g = nx.Graph() # 添加图的节点 g.add_node(2) g.add_node(5) # 添加图的边 g.add_edge(2, 5) g.add_edge(1, 4) # 当添加的边对应的节点不存在的时候,会自动创建相应的节点 g.add_edge(1, 2) g.add_edge(2, 6) # 绘制图 nx.draw(g)
图根据它的边是否具有指向性可以分为:
# 默认情况下,networkX 创建的是无向图 G = nx.Graph() print(G.is_directed()) # 创建有向图 H = nx.DiGraph() print(H.is_directed())
False True
根据图的边上权重是否为 1,我们可以将它们分为:
由于上面创建的图太小,为了方便计算图的性质,我们使用一个 NetworkX 中自带的图 The Karate Club Network(空手道俱乐部网络)进行学习。
空手道俱乐部网络是一个图表,描述了空手道俱乐部 34 名成员的社交网络,并记录了在俱乐部外互动的成员之间的链接。
# 创建一个空手道俱乐部网络 G = nx.karate_club_graph() # G is an undirected graph type(G) # 可视化图 nx.draw(G, with_labels = True)
# 网络平均度的计算 def average_degree(num_edges, num_nodes): # this function takes number of edges and number of nodes # returns the average node degree of the graph. # Round the result to nearest integer (for example 3.3 will be rounded to 3 and 3.7 will be rounded to 4) avg_degree = 0 ######################################### avg_degree = 2*num_edges/num_nodes avg_degree = int(round(avg_degree)) ######################################### return avg_degree num_edges = G.number_of_edges() num_nodes = G.number_of_nodes() avg_degree = average_degree(num_edges, num_nodes) print("Average degree of karate club network is {}".format(avg_degree))
Average degree of karate club network is 5
其中, p表示 p_{st} 中的一条路径,|p|是路径p的长度。
其中,E_i 表示节点 i 的邻居实际存在的边的数量,T_i 表示节点 i 的邻居可能(最多)存在的边的数量。
def average_clustering_coefficient(G): # this function that takes a nx.Graph # and returns the average clustering coefficient. # Round the result to 2 decimal places (for example 3.333 will be rounded to 3.33 and 3.7571 will be rounded to 3.76) avg_cluster_coef = 0 ######################################### ## Note: ## 1: Please use the appropriate NetworkX clustering function avg_cluster_coef = nx.average_clustering(G) avg_cluster_coef = round(avg_cluster_coef, 2) ######################################### return avg_cluster_coef avg_cluster_coef = average_clustering_coefficient(G) print("Average clustering coefficient of karate club network is {}".format(avg_cluster_coef))
Average clustering coefficient of karate club network is 0.57
def closeness_centrality(G, node=5): # the function that calculates closeness centrality # for a node in karate club network. G is the input karate club # network and node is the node id in the graph. Please round the # closeness centrality result to 2 decimal places. closeness = 0 ######################################### # Raw version following above equation # source: https://stackoverflow.com/questions/31764515/find-all-nodes-connected-to-n path_length_total = 0 for path in list(nx.single_source_shortest_path(G,node).values())[1:]: path_length_total += len(path)-1 closeness = 1 / path_length_total closeness = round(closeness, 2) return closeness node = 5 closeness = closeness_centrality(G, node=node) print("The karate club network has closeness centrality (raw) {:.2f}".format(closeness))
The karate club network has closeness centrality (raw) 0.01
# Normalized version from NetworkX # Notice that networkx closeness centrality returns the normalized # closeness directly, which is different from the raw (unnormalized) # one that we learned in the lecture. closeness = nx.closeness_centrality(G, node) print("The karate club network has closeness centrality (normalzied) {:.2f}".format(closeness))
The karate club network has closeness centrality (normalzied) 0.38
下面我们会介绍邻接矩阵、关联矩阵和拉普拉斯矩阵。一些文献会把他们归入图的性质中,但是因为它们是下面图神经网络中使用的重点,我们单独对它们进行更详细的讲解。
一个无向无权图的例子(左边为图,右边为图的邻接矩阵):
一个无向无权图的例子(左边为图,右边为图的邻接矩阵):
其中\mathbf{D=diag(d(v_1), \cdots, d(v_N))}是度矩阵。更具体地,我们记拉普拉斯矩阵中每一个元素为 L_{ij},那么每一个元素可以被定义为
它的每一行和列的加和为0。
按照不同的划分规则,图可以被划分为很多不同的种类。在 2.2 节中,我们根据边是否具有指向性,区分得到了有向图和无向图。下面,我们会根据更多不同的属性来对图进行划分。
根据图的拓扑结构,规则网络(regular network)可以分为
根据一些其他的不同性质,常见的图模型还有随机图(random graph)、小世界图(small world graph)和无标度图模型(scale-free graph)。
深度学习中的同质图和异质图和原本图理论中的定义稍有不同,这里我们只给出在深度学习中更常见的定义。
二分图或二部图(Bipartite Graphs):节点分为两类,只有不同类的节点之间存在边。
更具体地,二分图是一个网络,其节点可以分为两个不相交的集合 U 和 V,使得每个链接将 U 节点连接到 V 节点。换句话说,如果我们将 U 节点着色为绿色,将 V 节点着色为紫色,那么每个链接必须连接不同颜色的节点。我们可以为每个二分网络生成两个投影。如果两个 U 节点链接到二分表示中的相同 V 节点,则第一个投影通过链接连接两个 U 节点。如果它们连接到相同的 U 节点,则第二个投影通过链接连接 V 节点
# 创建一个二分图 Bipartite Graph from networkx.algorithms import bipartite B = nx.Graph() # Add nodes with the node attribute "bipartite" B.add_nodes_from([1, 2, 3, 4], bipartite=0) B.add_nodes_from(["a", "b", "c"], bipartite=1) # Add edges only between nodes of opposite node sets B.add_edges_from([(1, "a"), (1, "b"), (2, "b"), (2, "c"), (3, "c"), (4, "a")])
图深度学习从理论到实践 包勇军、朱小坤、颜伟鹏、姚普 清华大学出版社
Network Science by Albert-László Barabási http://networksciencebook.com/chapter/2
Fundamentals of Complex Networks: Models, Structures and Dynamics by Guanrong Chen. https://www.amazon.com/Fundamentals-Complex-Networks-Structures-Dynamics/dp/1118718119
Stanford CS224W: Machine Learning with Graphs https://web.stanford.edu/class/cs224w/
Datawhale 图神经网络组队学习 https://github.com/datawhalechina/team-learning-nlp/tree/master/GNN/
Deep Learning on Graphs by Yao Ma and Jiliang Tang https://web.njit.edu/~ym329/dlg_book/
图深度学习(Deep Learning on Graphs 中文版) 马耀、汤继良