datawhale-动手学图深度学习task02

动手学图深度学习task2

第二章:图理论基础

图的背景

图论中著名问题:柯尼斯堡七桥问题

  1. 问题:
    当时东普鲁士柯尼斯堡,市区跨普列戈利亚河两岸,河中心有两个小岛。小岛与河的两岸有七条桥连接。在所有桥都只能走一遍的前提下,如何才能把这个地方所有的桥都走遍?

  2. 解决思路:
    将问题简化为平面上点与线的组合,每一座桥视为一条线,桥所连接的地区视为点,从某点出发后最后再回到这点,则这一点的线数必须是偶数。

  3. 最终解决的法则:
    对于一个给定的连通图,如果存在超过两个的奇顶点,那么满足要求的路线便不存在了,且有n个奇顶点的图至少需要\(\lceil \frac{n}{2} \rceil\)笔画出,如果只有两个即顶点,则可从其中任何一地出发完成一幅画。若所有点均为偶顶点,则从任何一点出发,所求的路线都能实现。

图的定义

  1. 图被记为\(G = {V, E}\)
    其中\(V = {v_1, ... , v_N}\)是数量为\(N = |V|\)的节点(node/vertex)的集合。
    \(E = {e_1, ... , e_M}\)是数量为\(M\)的边(edge/link)的集合。

  2. 图用节点表示实体(entities),用边表示实体间的关系(relations)。

  3. 假如一条边\(e \in E\)连接两个节点\(v_1\)\(v_2\),那么这条边可以表示为\(e = (v_1, v_2)\)

  4. 节点和边的信息可以是类别型(categorical)的,取值是那一类别,其信息称为标签(label);也可以是数值型(numeric)的,取值范围为实数,其信息称为属性(attribute)。

  5. 在图的计算任务中,通常认为节点一定含有信息(至少含有节点的度的信息),边能含有信息。

  6. 图可以根据边是否具有指向性分为两类:

    • 有向图(directed graph / digraph):有向图的边具有指向性。
    • 无向图(undirected graph):无向图的边不具备指向性。
  7. 图可以根据边是否具有关联的数值(权重)分为两类:

    • 有权图(weighted graph):每条边都有权重、权重可以代表两个节点之间距离、连接强度、成本等任何有意义的量,且有权图边通常包括两个节点和它们的权重,例如\((v_A, v_B, 5)的权重记为w_{ij}\)
    • 无权图(unweighted graph):边无权重(在应用中所有边权重相同也可认为是无权图),边通常值包括两个节点之间存在一条边。
  8. 创建图的示例:

    # 创建一个图(无向无权图(权重默认为1))
    g = nx.Graph()
    
    # 添加图的节点
    g.add_node(2)
    g.add_node(5)
    
    # 添加图的边
    g.add_edge(2, 5, weight=4) # 图转变为有权图
    g.add_edge(1, 4) # 所需节点不存在时,自动创建相应的节点
    g.add_edge(1, 2)
    g.add_edge(2, 6)
    
    # 绘制图,默认无权重显示
    nx.draw(g)
    
    # 创建有向图:
    h = nx.DiGraph()
    
    # 判断是否有向:  
    >>> g.is_directed() #输出False
    
  9. nx.draw函数:

    '''  
    参数说明:
    - G=graph,要绘制的图,是一个nx图对象。  
    - pos=dictionary,指定了图中节点的位置,未指定则会使用一个默认布局,如spring_layout。    
    - ax=Matplotlib Axes object,允许你指定一个matplotlib轴对象,用于绘制图形,如果未指定,draw函数会创建一个新的图形和轴。如果想要在特定的轴上(已经存在的图形上)绘制图形,你可以传递这个轴对象。 
    以下为可选参数:  
        - with_labels=Bool,是否在节点旁边绘制标签,默认为True。  
        - arrows=Bool,是否在绘制时显示箭头,默认为False。  
        ...
    '''  
    
    # 以下有值的为默认值
    nx.draw(G, pos=None, ax=None, **kwds)
    

图的性质

以下示例均以networkx中自带图The Karate Club Network为例:G = nx.karate_club_graph()

  1. 邻接节点(neighbors):

    • 节点\(v_i\)的邻接节点是与节点\(v_i\)直接相连的节点,被记作\(N(v_i)\)
    • 节点\(v_i\)\(k\)跳远邻接节点(neighbors with k-pop)是到节点\(v_i\)要走k步的节点(一个节点的2跳远邻接节点包含了自身)。
  2. 图的度(degree):

    • 节点\(v_i\)的度记为\(d(v_i)\),入度记为\(d_{in}(v_i)\),出度记为\(d_{out}(v_i)\)
    • 有向有权图的节点\(v_i\)的出度(out degree)等于从\(v_i\)出发的边的权重之和,入度(in degree)同理;
    • 无向图的节点的出度和入度相同,无权图的节点\(v_i\)的出度等于从\(v_i\)出发的边的数量,入度同理;
    • 平均度(average degree)是一个表达网络整体性质的重要参数,无向图的平均度计算:\(\overline{d}(G)=\frac{1}{N}\sum^N_{i=1}d_i=\frac{2M}{N}\)
    • 度分布\(P(d)\)表示随机选择的节点的度为d的概率,平均度\(\overline{d}(G) = \sum^{\infty}_{d=0}dP(d)\)
  3. 图的平均度计算示例:

    # 手搓1
    def average_degree(num_edges, num_nodes):
        avg_degree = 2*num_edges/num_nodes
        return avg_degree
    
    num_edges = G.number_of_edges() # 获取边数  
    num_nodes = G.number_if_nodes() # 获取顶点数  
    avg_degree = average_degree(num_edges, num_nodes)
    
    # 手搓2  
    degrees = G.degree() # 获取图中{node: degree}
    average_degree = sum(degrees.values()) / len(degrees)
    
  4. 行走(walk)和路径(path):

    • \(walk(v_1, v_2) = (v_1, e_6, e_5, e_4, e_1, v_2)\)是从\(v_1\)出发,依次经过\(e6, e5, e4, e1\)到达\(v_2\)的行走(walk);
    • 在行走中,节点允许重复;
    • 路径是节点不可重复的行走。
  5. 距离(distance)和直径(diameter):

    • 最短路径(shortest path)被定义为两个点之间的距离。节点对\(v_s, v_t \in V\)之间的所有路径集合记为\(p_{st}\),这两节点中最短路径\(p^{sp}_{st}\)\(p_{st}\)中长度最短的一条路径,形式定义为$$p^{sp}{st} = \argmin{p \in p{st}}|p|$$
    • 直径是一个连通图所有节点对之间的最短路径的最大值,形式定义为$$diameter(G) = max_{v_s, v_t}min_{p \in p_{st}|p|}$$
  6. 子图(subgraph)、连通分量(connected component)和连通图(connected graph):

    • 子图:有一图\(G = {V, E}\),另一图\(G' = {V', E'}\),其中\(V' \in V,E' \in E\)\(V'\)不包含\(E'\)中为出现的节点,那么\(G'\)\(G\)的子图;
    • 连通分量:给定图\(G' = {V', E'}\)是另一图\(G = {V, E}\)的子图,记属于图\(G\)但不属于\(G'\)图的节点集合记为\(V \ V'\)。如果属于\(V'\)的任意节点对之间存在至少一条路径,但不存在一条边连接属于\(V'\)的节点与属于\(V \ V'\)的节点,那么图\(G'\)是图\(G\)的连通分量;
    • 连通图:当一个图只包含一个连通分量及其自身,那么该图是一个连通图。
  7. 聚类系数(Clustering Coefficient):

    • 聚类系数表示给定节点的邻居彼此链接的程度;
    • 节点\(i\)的邻域(通常指的是与该节点直接相邻的节点集合)互连越紧密,其局部聚类系数越高;
    • \(C_i\)是节点的两个邻居相互链接的概率;
    • 对于度数为\(d_i\)的节点\(i\),局部聚类系数定义为:

    \[C_i = \frac{E_i}{T_i} \]

    \(E_i\)表示节点\(i\)的邻居实际存在的边的数量,\(T_i\)表示节点\(i\)的邻居可能(最多)存在的边的数量。

    • 聚类系数\(C_i\)的值的含义:
      • \(C_i = 0\)如果节点\(i\)的邻居都没有相互链接;
      • \(C_i = 1\)如果节点\(i\)的邻居形成一个全连接图,即它们都相互链接;
      • \(C_i = 0.5\)意味着一个节点的两个邻居有50%的机会链接。
  8. 网络的聚类系数即平均聚类系数,是所有节点的集聚系数的平均值,计算公式为:

    \[C = \frac{1}{N}\sum_{i}C_i \]

    # 实现平均聚类系数计算函数:
    def average_clustering_coefficient(G):
        avg_cluster_coef = nx.average_clustering(G)
        return avg_cluster_coef
    
    avg_cluster_coef = average_clustering_cofficient(G)
    
  9. 接近中心度(closeness centrality):

    • 在连通图中,节点的接近中心性(接近性)是网络中中心性的度量,计算为该节点与图中所有其他节点之间的最短路径长度值和的倒数;

    • 节点越中心,它与所有其他节点越接近;

    • 接近中心度的计算公式:

      \[c(v) = \frac{1}{\sum_{u!=v}\text{shortest path length between u and v}} \]

    # 实现接近中心度计算函数  
    def closeness_centrality(G, node=5):
        closeness = 0
        path_length_total = 0
        # 计算图中节点node到其他所有节点的路径长度和([1:]是为了跳过计算node到它本身的路径长度)
        for path in list(nx.single_source_shortest_path(G, node).values())[1:]:
            # -1 是为了减去起点本身的长度
            path_length_total += len(path)-1
    
        closeness = 1 / path_length_total
    
        return closeness
    
    # nx内值函数(计算全图的时候省去node):  
    nx.closeness_centrality(G, node)
    
  10. 图的谱(spectrum):

    通常指的是图的特征值和特征向量;

    • 特征值:通常是指与图的邻接矩阵或拉普拉斯矩阵相关的特征值;
    • 特征向量:指的是与图的特征值相关联的向量,也就是图矩阵的特征向量;
    • 谱间隙(spectral gap):指邻接矩阵或拉普拉斯矩阵的特征值之间的差距,通常与图的扩张性有关,一般谱间隙大意味着图扩散性质较好;
    • 图的扩张性:描述了通过边的连接,一个小的顶点集如何扩展到整个图;
    • 谱定理:任何对称矩阵都可以被对角化为特征向量的矩阵与特征值对角矩阵的乘积;
    • 谱聚类:谱可以用于谱聚类算法,通过分析拉普拉斯矩阵的特征向量来发现图的社区结构;
    • 谱排序:谱可以用于顶点的排序问题,例如通过分析邻接矩阵的特征向量来进行网页排序;
    • 图同构:当且仅当两个图的邻接矩阵或拉普拉斯矩阵有相同的谱时两个图同构。

图的连接表示

  1. 邻接矩阵(Adjacenct Matrix):矩阵横纵代表vertex

    描述的是vertex和vertex之间的关系

    • 给定一个图\(G = {V, E}\),其对应邻接矩阵被记为\(A \in \{0, 1\}^{N*N}\)\(A_{i,j}=1\)表示存在从节点\(v_i\)\(v_j\)和节点\(v_j\)\(v_i\)的边,无向图的邻接矩阵是对称的;
    • 在无权图中,各条边的权重被认为是等价的,即认为各条边的权重为1;
    • 对于有权图,其对应的邻接矩阵通常被记为\(W \in \mathbb{R}^{N*N}\),其中\(W_{i,j} = w_{ij}\)表示从节点\(v_i\)\(v_j\)的边的权重,若边不存在,则其权重为0。
  2. 关联矩阵(Incidenct Matrix):矩阵横纵分别代表edge和vertex

    描述的是vertex和edge之间的关系

    • 给定一个图\(G = {V, E}\),其关联矩阵被记为\(I \in \{0, 1\}^{N*M}\)
    • \(I_{i,j}=1\)表示、节点\(v_i\)和边\(e_j\)相连接,反之则不连接。
  3. 拉普拉斯矩阵(Laplacian Matrix):

    描述的是图的结构特性与对应谱的特性之间的关系

    • 给定一个图\(G = {V, E}\),其对应邻接矩阵为\(A\),其拉普拉斯矩阵\(L\)定义为:

      \[L = D - A \]

    其中\(D = diag(d(v_1),...,d(v_N))\)是度矩阵;

    • 记拉普拉斯矩阵中每个元素为\(L_{ij}\),则每个元素可以被定义为:

      \[L = \begin{cases} \]

    -1 & \text{if } i \neq j \text{ and } v_i \text{ adjacent with } v_j\
    0 & \text{otherwise}
    \end{cases}$$

    • 对称归一化的拉普拉斯矩阵(Symmetric normalized Laplacian):给定一个图\(G = {V, E}\),其对应邻接矩阵为\(A\),其规范化(归一化)的拉普拉斯矩阵\(L\)定义为:

      \[L = D^{-\frac{1}{2}}(D - A)D^{-\frac{1}{2}}=I - D^{-\frac{1}{2}}AD^{-\frac{1}{2}} \]

图的类型

  1. 根据图的拓扑结构,规则网络(regular network)可以分为:

    • 全连接网络(fully-connected network);
    • 环形网络(ring-shape network);
    • 星形网络(start-shape network)。
  2. 根据图的连通性分类:

    • 连通图:图中任意两顶点都通过路径相互连接;
    • 非连通图:图中存在两个或多个不相连的顶点的集合;
    • 强连通图:有向图中,任意两个顶点之间都存在双向路径;
    • 弱连通图:有向图中,忽略边的方向后,图是连通的。
  3. 根据边和点的存在性分类:

    • 多重图:允许存在多条边连接同一对顶点;
    • 简单图:没有多重边和自环(即一个顶点指向自己的边)。
  4. 根据结构特性分类:

    • 树:无环连通图;
    • 森林:由多个不相连的树组成的图;
    • 二分图:顶点可以分成两个不相交的集合,使得每条边都连接这两个集合重中的顶点;
    • 平面图:可以在平面上画出的图,且任意两条边都不相交;
    • 图同构:拥有相同结构的图。
  5. 根据顶点的度分类:

    • 正则图:每个顶点都有相同度的图;
    • 二部图(二分图、Bipartite Graph):顶点可以分为两个集合,每个集合内的顶点之间没有边相连。
  6. 根据图谱特性分类:

    • 拉普拉斯谱图:根据拉普拉斯矩阵的特征值和特征向量分类;
    • 邻接谱图:根据邻接矩阵的特征值和特征向量分类。
  7. 根据动态特性分类:

    • 随机图(random graph):以随机方式生成的图;
    • 小世界图(small world graph):具有高聚类系数和低平均路径长度的图;
    • 尺度自由网络(无标度图、scale-free graph):顶点的度分布遵循幂律分布的图。
  8. 同质图(Homogeneous Graph)和1异质图(Heterogeneous Graph):

    • 同质图:只有一种类型的节点和一种类型的边的图;
    • 异质图:存在多种类型节点和多种类型的边的图。
  9. 二分图类似于投影关系,以下是代码实现:

    # 创建二分图
    from networkx.algorithms import bipartite  
    B = nx.Graph()
    
    # 增加点,可以使用add_nodes_from()添加多个点
    B.add_nodes_from([1, 2, 3, 4], bipartite=0)
    B.add_nodes_from(['a', 'b', 'c'], bipartite=1)
    
    # 增加边,可以使用add_edges_from()添加多个边
    B.add_edges_from([(1, 'a'), (1, 'b'), (2, 'c'), (3, 'c'), (4, 'a')])
    

您提供的数学表达式在语法上已经是正确的,它定义了一个图拉普拉斯矩阵(Laplacian matrix)。不过,为了提高可读性和清晰性,我们可以稍作改进,使其更加符合数学排版的标准。以下是改进后的表达式:

posted @ 2024-04-17 20:30  LPF05  阅读(9)  评论(0编辑  收藏  举报