图的基本数据结构

图的基本数据结构

本文主要内容来自datawhale开源课程

一、图的表示

定义一(图)

  • 一个图被记为 G = { V , E } \mathcal{G}=\{\mathcal{V}, \mathcal{E}\} G={V,E},其中 V = { v 1 , … , v N } \mathcal{V}=\left\{v_{1}, \ldots, v_{N}\right\} V={v1,,vN}是数量为 N = ∣ V ∣ N=|\mathcal{V}| N=V 的结点的集合, E = { e 1 , … , e M } \mathcal{E}=\left\{e_{1}, \ldots, e_{M}\right\} E={e1,,eM} 是数量为 M M M 的边的集合。
  • 图用节点表示实体(entities ),用边表示实体间的关系(relations)。
  • 节点和边的信息可以是类别型的(categorical),类别型数据的取值只能是哪一类别。一般称类别型的信息为标签(label)
  • 节点和边的信息可以是数值型的(numeric),类别型数据的取值范围为实数。一般称类别型的信息为属性(attribute)
  • 大部分情况中,节点含有信息,边可能含有信息。

定义二(图的邻接矩阵)

  • 给定一个图 G = { V , E } \mathcal{G}=\{\mathcal{V}, \mathcal{E}\} G={V,E},其对应的邻接矩阵被记为 A ∈ { 0 , 1 } N × N \mathbf{A} \in\{0,1\}^{N \times N} A{0,1}N×N A i , j = 1 \mathbf{A}_{i, j}=1 Ai,j=1表示存在从结点 v i v_i vi v j v_j vj的边,反之表示不存在从结点 v i v_i vi v j v_j vj的边。

  • 无向图中,从结点 v i v_i vi v j v_j vj的边存在,意味着从结点 v j v_j vj v i v_i vi的边也存在。因而无向图的邻接矩阵是对称的

  • 无权图中,各条边的权重被认为是等价的,即认为各条边的权重为 1 1 1

  • 对于有权图,其对应的邻接矩阵通常被记为 W ∈ { 0 , 1 } N × N \mathbf{W} \in\{0,1\}^{N \times N} W{0,1}N×N,其中 W i , j = w i j \mathbf{W}_{i, j}=w_{ij} Wi,j=wij表示从结点 v i v_i vi v j v_j vj的边的权重。若边不存在时,边的权重为 0 0 0

    一个无向无权图的例子:

在这里插入图片描述

其邻接矩阵为:
A = ( 0 1 0 1 1 1 0 1 0 0 0 1 0 0 1 1 0 0 0 1 1 0 1 1 0 ) \mathbf{A}=\left(\begin{array}{lllll} 0 & 1 & 0 & 1 & 1 \\ 1 & 0 & 1 & 0 & 0 \\ 0 & 1 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 & 1 \\ 1 & 0 & 1 & 1 & 0 \end{array}\right) A=0101110100010011000110110

二、图的属性

定义三(结点的度,degree)

  • 对于有向有权图,结点 v i v_i vi的出度(out degree)等于从 v i v_i vi出发的边的权重之和,结点 v i v_i vi的入度(in degree)等于从连向 v i v_i vi的边的权重之和。
  • 无向图是有向图的特殊情况,结点的出度与入度相等。
  • 无权图是有权图的特殊情况,各边的权重为 1 1 1,那么结点 v i v_i vi的出度(out degree)等于从 v i v_i vi出发的边的数量,结点 v i v_i vi的入度(in degree)等于从连向 v i v_i vi的边的数量。
  • 结点 v i v_i vi的度记为 d ( v i ) d(v_i) d(vi),入度记为 d i n ( v i ) d_{in}(v_i) din(vi),出度记为 d o u t ( v i ) d_{out}(v_i) dout(vi)

定义四(邻接结点,neighbors)

  • 结点 v i v_i vi的邻接结点为与结点 v i v_i vi直接相连的结点,其被记为** N ( v i ) \mathcal{N(v_i)} N(vi)**。
  • **结点 v i v_i vi k k k跳远的邻接节点(neighbors with k k k-hop)**指的是到结点 v i v_i vi要走 k k k步的节点(一个节点的 2 2 2跳远的邻接节点包含了自身)。

定义五(行走,walk)

  • w a l k ( v 1 , v 2 ) = ( v 1 , e 6 , e 5 , e 4 , e 1 , v 2 ) walk(v_1, v_2) = (v_1, e_6,e_5,e_4,e_1,v_2) walk(v1,v2)=(v1,e6,e5,e4,e1,v2),这是一次“行走”,它是一次从节点 v 1 v_1 v1出发,依次经过边 e 6 , e 5 , e 4 , e 1 e_6,e_5,e_4,e_1 e6,e5,e4,e1,最终到达节点 v 2 v_2 v2的“行走”。
  • 下图所示为 w a l k ( v 1 , v 2 ) = ( v 1 , e 6 , e 5 , e 4 , e 1 , v 2 ) walk(v_1, v_2) = (v_1, e_6,e_5,e_4,e_1,v_2) walk(v1,v2)=(v1,e6,e5,e4,e1,v2),其中红色数字标识了边的访问序号。
  • 在“行走”中,节点是运行重复的。

在这里插入图片描述

定义六

  • 有一图,其邻接矩阵为 A \mathbf{A} A, A n \mathbf{A}^{n} An为邻接矩阵的 n n n次方,那么 A n [ i , j ] \mathbf{A}^{n}[i,j] An[i,j]等于从结点 v i v_i vi到结点 v j v_j vj的长度为 n n n的行走的个数。

定义七(路径,path)

  • “路径”是结点不可重复的“行走”。

定义八(子图,subgraph)

  • 有一图 G = { V , E } \mathcal{G}=\{\mathcal{V}, \mathcal{E}\} G={V,E},另有一图 G ′ = { V ′ , E ′ } \mathcal{G}^{\prime}=\{\mathcal{V}^{\prime}, \mathcal{E}^{\prime}\} G={V,E},其中 V ′ ∈ V \mathcal{V}^{\prime} \in \mathcal{V} VV E ′ ∈ E \mathcal{E}^{\prime} \in \mathcal{E} EE并且 V ′ \mathcal{V}^{\prime} V不包含 E ′ \mathcal{E}^{\prime} E中未出现过的结点,那么 G ′ \mathcal{G}^{\prime} G G \mathcal{G} G的子图。

定义九(连通分量,connected component)

  • 给定图 G ′ = { V ′ , E ′ } \mathcal{G}^{\prime}=\{\mathcal{V}^{\prime}, \mathcal{E}^{\prime}\} G={V,E}是图 G = { V , E } \mathcal{G}=\{\mathcal{V}, \mathcal{E}\} G={V,E}的子图。记属于图 G \mathcal{G} G但不属于 G ′ \mathcal{G}^{\prime} G图的结点集合记为 V / V ′ \mathcal{V}/\mathcal{V}^{\prime} V/V 。如果属于 V ′ \mathcal{V}^{\prime} V的任意结点对之间存在至少一条路径,但不存在一条边连接属于 V ′ \mathcal{V}^{\prime} V的结点与属于 V / V ′ \mathcal{V}/\mathcal{V}^{\prime} V/V的结点,那么图 G ′ \mathcal{G}^{\prime} G是图 G \mathcal{G} G的连通分量。

在这里插入图片描述

左右两边子图都是整图的连通分量。

定义十(连通图,connected graph)

  • 当一个图只包含一个连通分量,即其自身,那么该图是一个连通图。

定义十一(最短路径,shortest path)

  • v s , v t ∈ V v_{s}, v_{t} \in \mathcal{V} vs,vtV 是图 G = { V , E } \mathcal{G}=\{\mathcal{V}, \mathcal{E}\} G={V,E}上的一对结点,结点对 v s , v t ∈ V v_{s}, v_{t} \in \mathcal{V} vs,vtV之间所有路径的集合记为 P s t \mathcal{P}_{\mathrm{st}} Pst。结点对 v s , v t v_{s}, v_{t} vs,vt之间的最短路径 p s t s p p_{\mathrm{s} t}^{\mathrm{sp}} pstsp P s t \mathcal{P}_{\mathrm{st}} Pst中长度最长的一条路径,其形式化定义为
    p s t s p = arg ⁡ min ⁡ p ∈ P s t ∣ p ∣ p_{\mathrm{s} t}^{\mathrm{sp}}=\arg \min _{p \in \mathcal{P}_{\mathrm{st}}}|p| pstsp=argpPstminp
    其中, p p p表示 P s t \mathcal{P}_{\mathrm{st}} Pst中的一条路径, ∣ p ∣ |p| p是路径 p p p的长度。

定义十二(直径,diameter)

  • 给定一个连通图 G = { V , E } \mathcal{G}=\{\mathcal{V}, \mathcal{E}\} G={V,E},其直径为其所有结点对之间的最短路径的最小值,形式化定义为

diameter ⁡ ( G ) = max ⁡ v s , v t ∈ V min ⁡ p ∈ P s t ∣ p ∣ \operatorname{diameter}(\mathcal{G})=\max _{v_{s}, v_{t} \in \mathcal{V}} \min _{p \in \mathcal{P}_{s t}}|p| diameter(G)=vs,vtVmaxpPstminp

定义十三(拉普拉斯矩阵,Laplacian Matrix)

  • 给定一个图 G = { V , E } \mathcal{G}=\{\mathcal{V}, \mathcal{E}\} G={V,E},其邻接矩阵为 A A A,其拉普拉斯矩阵定义为 L = D − A \mathbf{L=D-A} L=DA,其中 D = d i a g ( d ( v 1 ) , ⋯   , d ( v N ) ) \mathbf{D=diag(d(v_1), \cdots, d(v_N))} D=diag(d(v1),,d(vN))

定义十四(对称归一化的拉普拉斯矩阵,Symmetric normalized Laplacian)

  • 给定一个图 G = { V , E } \mathcal{G}=\{\mathcal{V}, \mathcal{E}\} G={V,E},其邻接矩阵为 A A A,其规范化的拉普拉斯矩阵定义为

L = D − 1 2 ( D − A ) D − 1 2 = I − D − 1 2 A D − 1 2 \mathbf{L=D^{-\frac{1}{2}}(D-A)D^{-\frac{1}{2}}=I-D^{-\frac{1}{2}}AD^{-\frac{1}{2}}} L=D21(DA)D21=ID21AD21

三、图的种类

  • 同质图(Homogeneous Graph):只有一种类型的节点和一种类型的边的图。

  • 异质图(Heterogeneous Graph):存在多种类型的节点和多种类型的边的图。
    在这里插入图片描述

  • 二部图(Bipartite Graphs):节点分为两类,只有不同类的节点之间存在边。
    在这里插入图片描述

四、图结构数据上的机器学习

在这里插入图片描述

  1. 节点预测:预测节点的类别或某类属性的取值
    1. 例子:对是否是潜在客户分类、对游戏玩家的消费能力做预测
  2. 边预测:预测两个节点间是否存在链接
    1. 例子:Knowledge graph completion、好友推荐、商品推荐
  3. 图的预测:对不同的图进行分类或预测图的属性
    1. 例子:分子属性预测
  4. 节点聚类:检测节点是否形成一个社区
    1. 例子:社交圈检测
  5. 其他任务
    1. 图生成:例如药物发现
    2. 图演变:例如物理模拟
    3. ……

五、应用神经网络于图面临的挑战

在学习了简单的图论知识,我们再来回顾应用神经网络于图面临的挑战。

过去的深度学习应用中,我们主要接触的数据形式主要是这四种:矩阵、张量、序列(sequence)和时间序列(time series)它们都是规则的结构化的数据。然而图数据是非规则的非结构化的,它具有以下的特点:

  1. 任意的大小和复杂的拓扑结构;
  2. 没有固定的结点排序或参考点;
  3. 通常是动态的,并具有多模态的特征;
  4. 图的信息并非只蕴含在节点信息和边的信息中,图的信息还包括了图的拓扑结构。

在这里插入图片描述

以往的深度学习技术是为规则且结构化的数据设计的,无法直接用于图数据。应用于图数据的神经网络,要求

  • 适用于不同度的节点
  • 节点表征的计算与邻接节点的排序无关
  • 不但能够根据节点信息、邻接节点的信息和边的信息计算节点表征,还能根据图拓扑结构计算节点表征。下面的图片展示了一个需要根据图拓扑结构计算节点表征的例子。图片中展示了两个图,它们同样有俩黄、俩蓝、俩绿,共6个节点,因此它们的节点信息相同;假设边两端节点的信息为边的信息,那么这两个图有一样的边,即它们的边信息相同。但这两个图是不一样的图,它们的拓扑结构不一样。

在这里插入图片描述

六、pytorch_geometric学习

本节主要内容来自pytorch-geometric

Data Handling of Graphs

A graph is used to model pairwise relations (edges) between objects (nodes). A single graph in PyTorch Geometric is described by an instance of torch_geometric.data.Data, which holds the following attributes by default:
图形用于建立对象(节点)之间的成对关系(边)模型。PyTorch Geometric中的单个图形由torchïu Geometric.data.data的实例描述,默认情况下,该实例包含以下属性:

data.x: Node feature matrix with shape [num_nodes, num_node_features]
x (Tensor, optional): 节点属性矩阵,大小为[num_nodes, num_node_features]
data.edge_index: Graph connectivity in COO format with shape [2, num_edges] and type torch.long
edge_index (LongTensor, optional): 边索引矩阵,大小为[2, num_edges]
data.edge_attr: Edge feature matrix with shape [num_edges, num_edge_features]
edge_attr (Tensor, optional): 边属性矩阵,大小为[num_edges, num_edge_features]``edge_index的每一列定义一条边,其中第一行为边起始节点的索引,第二行为边结束节点的索引。这种表示方法被称为COO格式(coordinate format),通常用于表示稀疏矩阵。PyG不是用稠密矩阵 A ∈ { 0 , 1 } ∣ V ∣ × ∣ V ∣ \mathbf{A} \in \{ 0, 1 \}^{|\mathcal{V}| \times |\mathcal{V}|} A{0,1}V×V来持有邻接矩阵的信息,而是用仅存储邻接矩阵 A \mathbf{A} A中非 0 0 0元素的稀疏矩阵来表示图。
data.y: Target to train against (may have arbitrary shape), e.g., node-level targets of shape [num_nodes, *] or graph-level targets of shape [1, *]
y (Tensor, optional): 节点或图的标签,任意大小(其实也可以是边的标签)
通常,一个图至少包含x, edge_index, edge_attr, y, num_nodes5个属性,当图包含其他属性时,我们可以通过指定额外的参数使Data对象包含其他的属性

graph = Data(x=x, edge_index=edge_index, edge_attr=edge_attr, y=y, num_nodes=num_nodes, other_attr=other_attr)

example

import torch
from torch_geometric.data import Data

edge_index = torch.tensor([[0, 1, 1, 2],
                           [1, 0, 2, 1]], dtype=torch.long)
x = torch.tensor([[-1], [0], [1]], dtype=torch.float)

data = Data(x=x, edge_index=edge_index)

图结构如下图所示:
在这里插入图片描述

7、作业实践

请通过继承Data类实现一个类,专门用于表示“机构-作者-论文”的网络。该网络包含“机构“、”作者“和”论文”三类节点,以及“作者-机构“和“作者-论文“两类边。对要实现的类的要求:1)用不同的属性存储不同节点的属性;2)用不同的属性存储不同的边(边没有属性);3)逐一实现获取不同节点数量的方法。

class Data(object):

    def __init__(self, x_institution=None, x_author=None, x_thesis=None, edge_au_ins=None, edge_au_th=None, y=None, **kwargs):
        r"""
        Args:
            x_institution (Tensor, optional): 节点属性矩阵,大小为`[num_nodes, num_node_features]`
            x_author (Tensor, optional): 节点属性矩阵,大小为`[num_nodes, num_node_features]`
            x_thesis (Tensor, optional): 节点属性矩阵,大小为`[num_nodes, num_node_features]`
            edge_au_ins (LongTensor, optional): 边索引矩阵,大小为`[2, num_edges]`,第0行为尾节点,第1行为头节点,头指向尾
            edge_au_th (LongTensor, optional): 边索引矩阵,大小为`[2, num_edges]`,第0行为尾节点,第1行为头节点,头指向尾
            y (Tensor, optional): 节点或图的标签,任意大小(,其实也可以是边的标签)

        """
        self.x_institution = x_institution
        self.x_author = x_author
        self.x_thesis = x_thesis
        self.edge_au_ins = edge_au_ins
        self.edge_au_th = edge_au_th
        self.y = y

        for key, item in kwargs.items():
            if key == 'num_nodes':
                self.__num_nodes__ = item
            else:
                self[key] = item
    def len_x_institution(self):
        return self.x_institution.shape[0]
    def len_x_author(self):
        return self.x_author.shape[0]
    def len_x_thesis(self):
        return self.x_thesis.shape[0]

import torch
if __name__ == "__main__":
    x_institution = torch.tensor([[-1]], dtype=torch.long)
    x_author = torch.tensor([[-1],[0]], dtype=torch.long)
    x_thesis = torch.tensor([[-1],[0]], dtype=torch.long)
    edge_au_ins = torch.tensor([[0,1],
                            [1,0]], dtype=torch.float)
    edge_au_th = torch.tensor([[1,3,2,4],
                            [4,2,3,1]], dtype=torch.float)
    data = Data(x_institution,x_author,x_thesis,edge_au_ins,edge_au_th)  # Get the graph object.
    print(data)
    print('==============================================================')

    # 获取图的一些信息
    print(f'Number of nodes: {data.len_x_institution()}') # 机构节点数量
    print(f'Number of nodes: {data.len_x_author()}') # 作者节点数量
    print(f'Number of nodes: {data.len_x_thesis()}') # 论文节点数量
'''
output:
<__main__.Data object at 0x7f4363583f10>
==============================================================
Number of nodes: 1
Number of nodes: 2
Number of nodes: 2
'''

参考资料

  1. datawhale开源课程
  2. https://pytorch-geometric.readthedocs.io/en/latest/notes/introduction.html
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值