本文将探讨如何使用Python,特别是NumPy和NetworkX库,来创建和可视化各种图结构。图网络在表示不同领域(如社交网络、网页、交通系统和学术联系)中的关系的作用非常重要。本文将介绍如何使用NumPy构建邻接矩阵,以描述图的连通性,并利用NetworkX可视化这些结构。本文涵盖了无向图(具有对称关系)、有向图(具有单向连接)、加权图(具有不同边缘成本)以及异构图(具有多种节点和边缘类型)的创建。每种图类型都通过代码示例和可视化的形式进行说明,希望帮助读者理解和使用图数据结构。

图网络的重要性
图是表示各种领域(包括社交网络、网页、交通网络和学术联系)中实体之间关系的基本数据结构。这些领域中的关系是不同的,因此我们需要采用不同类型的图来尽可能接近这些连接的本质。
理解连通性结构(如邻接矩阵或类似的数据结构,如边索引张量)的作用对于掌握图神经网络(GNNs)等高级图机器学习技术背后的关键思想至关重要。
在深入构建这些图网络之前,使用如下代码导入必要的库并显示图形。
# Import necessary librariesimport numpy as npimport networkx as nximport matplotlib.pyplot as plt# Global color propertiesgraph_color = "#4986e8"label_color = "#ffffff"node_options = { 'node_color': graph_color, 'node_size': 1000, 'edgecolors': 'black', 'linewidths': 2,}# Helper function to draw any graphdef draw_graph(G, node_options, edge_options, edge_labels=None): """ Draws the graph G with the specified node and edge options. Parameters: G (networkx.Graph): The graph to be drawn. node_options (dict): Options for drawing nodes. edge_options (dict): Options for drawing edges. edge_labels (dict, optional): Labels for the edges. Defaults to None. """ # Define the layout of the graph pos = nx.spring_layout(G, iterations=10, seed=20000) # Draw the nodes with the specified options nx.draw_networkx_nodes(G, pos, **node_options) # Draw the node labels with specified font properties nx.draw_networkx_labels( G, pos, font_size=14, font_color=label_color, font_weight='bold' ) # Draw the edges with the specified options nx.draw_networkx_edges(G, pos, **edge_options) # Draw edge labels if they are provided if edge_labels: nx.draw_networkx_edge_labels( G, pos, edge_labels=edge_labels, connectionstyle="arc3, rad=0.3", font_size=12, font_color="orange", bbox={"alpha": 1, "color": "white"} ) # Turn off the axis and ensure the graph aspect ratio is equal plt.axis('off') plt.gca().set_aspect('equal') # Display the graph plt.show()这段代码提供了一个函数,帮助我们以一致的风格绘制不同的图。该函数允许我们灵活地定义节点的视觉选项,更重要的是,可以根据我们想要表示的图的类型定义边的视觉选项。
重要图网络类型
现在,让我们介绍用于描述不同现象的最重要的图类型,理解它们的特性,并提供一个通用框架,以便建模和可视化它们的特征
无向图(Undirected Graph)
无向图是一种图,其中边没有方向。换句话说,如果在无向图中存在一条连接顶点0和顶点1的边,则1和0之间存在对称关系。例如,在社交网络中,两个人之间的友谊是相互的:如果小张是小李的朋友,那么小李也是小张的朋友。这种关系可以有效地使用无向图来建模,其中节点表示人,边表示友谊。以下代码展示了如何使用NetworkX库从使用NumPy构建的邻接矩阵开始,构建和可视化一个无向图。
我们通过特定步骤构建了我们的邻接矩阵,以实现我们的目标(在接下来的示例中,我们将直接从预定义的数据结构开始)。从之前的脚本获得的邻接矩阵如下:
# Adjacency matrix (randomly initialized)np.random.seed(1)n = 5A = np.random.randint(2, size=(n, n))# Include the self loopnp.fill_diagonal(A, 1)# Hack for creating a symmetric adjacency matrixA = (A + A.T)A[A > 1] = 1这个邻接矩阵表示一个具有5个节点(标记为0到4)的无向图。我们的邻接矩阵也是对称的,以反映无向图的对称特性。对称矩阵是一个在对角线两侧值相同的方阵。这意味着第i行第j列的值与第j行第i列的值相同。
array([[1, 1, 0, 0, 1], [1, 1, 1, 1, 1], [0, 1, 1, 1, 1], [0, 1, 1, 1, 0], [1, 1, 1, 0, 1]])以下是基于该矩阵对节点之间连接的简单描述:
- 节点0与自身(0 → 0)、节点1(0 → 1)和节点4(0 → 4)有边连接。
- 节点1是完全连接的,与所有节点(包括自身)都有边连接。这意味着节点1与节点0(1 → 0)、节点1自身(1 → 1)、节点2(1 → 2)、节点3(1 → 3)和节点4(1 → 4)都有边连接。
- 节点2与节点1(2 → 1)、自身(2 → 2)、节点3(2 → 3)和节点4(2 → 4)有边连接。
- 节点3与节点1(3 → 1)、自身(3 → 3)和节点2(3 → 2)有边连接。
- 节点4与节点0(4 → 0)、节点1(4 → 1)、节点2(4 → 2)和自身(4 → 4)有边连接。
现在让我们定义绘制无向图的基本边选项:
G = nx.from_numpy_array(A)edge_options = { 'edge_color': graph_color, 'width': 2.5, 'alpha': 0.7,}draw_graph(G, node_options, edge_options)上述代码输出结果如图:

上图中,每个节点都与图中一部分节点相连,并始终与自身相连。这个最后的连接可以直接从邻接矩阵中得出,其中对角线上的所有值都等于1。
有向图(Directed Graph)
有向图是一种图,其中边具有特定的方向。在有向图中,每条边用箭头表示,指示连接的顶点之间关系的方向。
例如,如果存在一条从顶点0指向顶点1的有向边,则表示从0到1的单向关系或连接,而这条边不一定可以反向遍历或解释。在网页的超链接结构中,如果网页A链接到网页B,并不一定意味着B会链接回A。这种不对称和有方向的关系使得有向图成为一个合适的模型。
在这里,节点表示网页,有向边表示从一个页面到另一个页面的超链接。以下代码演示了如何从一个非对称的邻接矩阵构建有向图。
A = np.array([ [0, 1, 0, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [1, 0, 0, 0, 0]])这个邻接矩阵表示一个具有5个节点(标记为0到4)的有向图。以下是基于该矩阵对节点之间连接的简单描述:
- 节点0有边连接到节点1(0 → 1)和节点3(0 → 3)。
- 节点1有边连接到节点2(1 → 2)和节点4(1 → 4)。
- 节点2有边连接到节点3(2 → 3)。
- 节点3有边连接到节点4(3 → 4)。
- 节点4有边连接到节点0(4 → 0),形成一个循环。
现在,让我们更新并扩展之前的边选项,以绘制我们的有向图,并清晰地显示边的方向。
G = nx.from_numpy_array(A, create_using=nx.DiGraph())edge_options = { 'edge_color': graph_color, 'width': 2.5, 'alpha': 0.7, 'connectionstyle': 'arc3, rad = 0.3', 'arrowstyle': '-|>', 'arrowsize': 30}draw_graph(G, node_options, edge_options)上述代码的输出结果如下图:

从上图可以看出,与之前展示的无向图相比,我们没有自环连接。这一点从邻接矩阵中可以明显看出,其中对角线上的所有值都等于0。
加权图(Weighted Graph)
加权图是一种图,其中每条边都被赋予一个称为权重的数值。这些权重表示与遍历该边相关的某种“成本”、“距离”、“容量”或其他相关度量。
在交通网络中,连接城市的道路具有不同的长度或旅行时间。加权图用于表示城市(节点)之间的道路(边)。在这种情况下,边上的权重可以表示沿该道路的距离、旅行时间或旅行成本。
以下代码演示了如何通过定义一个邻接矩阵来构建加权图,其中的值可以大于1。
A = np.array([ [0, 2, 0, 3, 0], [0, 0, 1, 0, 4], [0, 0, 0, 5, 0], [0, 0, 0, 0, 6], [7, 0, 0, 0, 0]])这个邻接矩阵表示一个具有5个节点(标记为0到4)的有向加权图。矩阵中的权重表示节点之间连接(边)的强度或成本。以下是基于该矩阵对节点之间连接的描述:
- 节点0与节点1之间有一条权重为2的边(0 → 1,权重2),与节点3之间有一条权重为3的边(0 → 3,权重3)。
- 节点1与节点2之间有一条权重为1的边(1 → 2,权重1),与节点4之间有一条权重为4的边(1 → 4,权重4)。
- 节点2与节点3之间有一条权重为5的边(2 → 3,权重5)。
- 节点3与节点4之间有一条权重为6的边(3 → 4,权重6)。
- 节点4与节点0之间有一条权重为7的边(4 → 0,权重7),形成一个循环。
现在,让我们创建边的选项,以绘制我们的有向加权图,并定义边的粗细。
G = nx.from_numpy_array(A, create_using=nx.DiGraph())weights = nx.get_edge_attributes(G, 'weight')edge_options = { 'edge_color': graph_color, 'width': 2.5, 'alpha': 0.7, 'connectionstyle': 'arc3, rad = 0.1', 'arrowstyle': '-|>', 'arrowsize': 30, 'width': [weights[edge] for edge in G.edges()]}draw_graph(G, node_options, edge_options)上述代码的输出结果如下图:

异构图(Heterogeneous Graph)
异构图是一种节点和边可以有不同类型或属性的图。在这种图中,节点可以表示各种实体或对象,边可以表示这些实体之间的不同关系或交互。
例如,在学术知识图谱中,有多种类型的实体(如论文、作者、机构)和不同类型的关系(如作者撰写论文、论文引用另一篇论文、作者隶属于某个机构)。异构图可以捕捉这些关系的复杂性,节点有不同的类型,边表示各种类型的连接。
以下代码演示了如何构建和可视化一个具有多种关系类型的异构图。在这个例子中,我们使用了一种不同的方法来构建NetworkX库的输入数据。
A = { 'type1': np.array([ [0, 1, 0], [0, 0, 1], [0, 0, 0] ]), 'type2': np.array([ [0, 0, 1], [1, 0, 0], [0, 1, 0] ])}在这种情况下,我们指定一个Python字典来定义每种关系的邻接矩阵。更具体地说,对于type1关系,我们有以下连接:
- 节点0与节点1之间有一条边(0 → 1)。
- 节点1与节点2之间有一条边(1 → 2)。
- 节点2与任何其他节点没有连接。
对于type2关系,我们有以下连接:
- 节点0与节点2之间有一条边(0 → 2)。
- 节点1与节点0之间有一条边(1 → 0)。
- 节点2与节点1之间有一条边(2 → 1)。
我们可以采用一种更适合机器学习的解决方案来表示不同类型的边,例如创建一个三维张量。
我们使用NetworkX中构建图,以显示具有不同类型边的异构图。
# Create a heterogeneous graph using NetworkXG = nx.MultiDiGraph()# Add nodesnum_nodes = A['type1'].shape[0]G.add_nodes_from(range(num_nodes))# Add edges from each adjacency matrixfor edge_type, adj_matrix in A.items(): for i in range(num_nodes): for j in range(num_nodes): if adj_matrix[i, j] != 0: G.add_edge(i, j, type=edge_type)edge_labels = nx.get_edge_attributes(G,'type')edge_options = { 'edge_color': graph_color, 'width': 2.5, 'alpha': 0.7, 'connectionstyle': 'arc3, rad = 0.3', 'arrowstyle': '-|>', 'arrowsize': 30,}draw_graph(G, node_options, edge_options, edge_labels=edge_labels)上述代码的输出结果如下图:

总结
本文介绍了如何使用Python,特别是NumPy和NetworkX,来表示和可视化各种图。文章涵盖了无向图、有向图、加权图和异构图,每种图在建模现实世界关系中都有不同的用途。

本公众号相关内容推荐:
- OpenResearcher:一个开源科学研究AI助理
- NeuralGCM: 一种融合机器学习与物理原理来模拟地球大气的新方法
- Transformer Explainer:文本生成模型交互式可视化工具
- 用于探索性数据分析(EDA)的开源python库
- 分享一个构建交互式D3js可视化的Python库
- 推荐15个图网络可视化python软件包
- 9个提升科研效率的软件工具
- 生成式人工智能模型颠覆传统天气预报
- 分享5个python可视化图表工具
- 分享17个网络(Network)数据可视化工具
- Napari:一个支持分析大型多维图像数据集的python工具
- 地理空间数据分析可视化R软件包汇总
- 大气海洋科学数据可视化案例集#2
- 一个快速检索和下载NASA地球科学数据的Python软件包
- 可视化呈现海洋洋流-墨西哥湾流
- 探索NOAA提供的数据产品资源
- 全球海洋船舶定位数据交互式可视化(附数据)
- 地球科学领域开源python包#1
- 地球科学领域开源python包#2
- 大规模空间矢量数据可视化Python库-lonboard
- 可视化呈现2023年是有气象记录以来最热的一年
- 大气海洋科学数据可视化案例集#1
- 地球科学领域计算分析开源Julia软件包
- 地球观测数据可视化工具
- 地球科学领域计算分析开源Julia软件包