杰瑞科技汇

Python中MultiDigraph如何高效处理多边有向图?

MultiDiGraph 是一个非常强大的数据结构,它属于有向多重图,为了完全理解它,我们把它拆分成三个关键词:

Python中MultiDigraph如何高效处理多边有向图?-图1
(图片来源网络,侵删)
  1. :由一组顶点和连接这些顶点的边组成的网络结构。
  2. 有向:边是有方向的,如果从节点 A 到节点 B 有一条有向边,我们只能从 A 到达 B,而不能直接从 B 到达 A,在 Python 的 networkx 库中,这通常用元组 (u, v) 表示,u 是起点,v 是终点。
  3. 多重:在任意两个节点之间,可以存在多条边,这与普通的“简单图”(Simple Graph)不同,简单图中两个节点之间最多只能有一条边。
特性 描述
节点 图中的基本元素,可以代表任何对象(如人、城市、单词等)。
连接两个节点的线段,有方向
多重边 关键特性:允许两个节点之间存在多条方向相同的边,每条边都是独立的。

主要应用场景

MultiDiGraph 非常适合那些需要用多条、有方向的连接来建模复杂关系的场景。

  1. 交通网络:从一个城市(节点 A)到另一个城市(节点 B),可以有多条不同的航线(多条边),每条航线都有其特定的航班号和时刻表。
  2. 工作流:在一个工作流程中,一个任务(节点 A)完成后,可以触发两个并行的后续任务(节点 B 和 C),或者,两个不同的前置任务(节点 A 和 D)都可以触发同一个后续任务(节点 B)。
  3. 数据流图:在机器学习模型中,一个特征(节点 A)可能通过两个不同的预处理步骤(两条边)影响最终的预测(节点 B)。
  4. 社交网络:用户 A 可以给用户 B 发送多条私信(多条边),或者用户 A 和 B 之间可以有多个不同类型的互动(如“点赞”、“评论”、“转发”)。
  5. 化学反应:一种反应物(节点 A)可以在不同催化剂(不同边)的作用下,生成同一种产物(节点 B)。

Python 实现 (使用 networkx 库)

在 Python 中,最常用和最强大的图论库是 networkx,它提供了 MultiDiGraph 类。

安装 networkx

如果你还没有安装,请先安装它:

pip install networkx

创建和基本操作

import networkx as nx
import matplotlib.pyplot as plt
# 1. 创建一个空的 MultiDiGraph
G = nx.MultiDiGraph()
# 2. 添加节点
# 节点可以是任何可哈希的 Python 对象,如字符串、数字
G.add_node("A")
G.add_node("B")
G.add_node("C")
# 3. 添加边
# 这是 MultiDiGraph 的核心:可以在相同的 (u, v) 对上添加多条边
# networkx 会自动为它们分配一个唯一的键,通常是整数
G.add_edge("A", "B")  # 第一条从 A 到 B 的边
G.add_edge("A", "B")  # 第二条从 A 到 B 的边
G.add_edge("B", "C")  # 第一条从 B 到 C 的边
G.add_edge("A", "C")  # 一条从 A 直接到 C 的边
# 4. 添加带属性的边
# 你可以为每条边添加一个字典来存储其属性,如 'weight', 'label', 'flight_id' 等
G.add_edge("B", "C", weight=5, label="fast_route")
G.add_edge("B", "C", weight=1, label="scenic_route")
# 5. 查看图的信息
print(f"节点列表: {list(G.nodes())}")
print(f"边列表: {list(G.edges())}")
print("-" * 20)
# 6. 访问特定的边
# 对于多重边,G.edges() 会返回所有边,包括重复的
print("所有边(包括多重边):")
for u, v, key in G.edges(keys=True):
    # key 是 networkx 为多重边分配的唯一标识符
    edge_data = G.edges[u, v, key]
    print(f"  边: {u} -> {v}, 键: {key}, 属性: {edge_data}")
print("-" * 20)
# 7. 获取两个节点之间的所有边
# 使用 G.get_edge_data(u, v) 返回一个字典,键是边的 key,值是边的属性
edges_between_b_and_c = G.get_edge_data("B", "C")
print("从 B 到 C 的所有边及其属性:")
for key, data in edges_between_b_and_c.items():
    print(f"  键: {key}, 属性: {data}")
print("-" * 20)
# 8. 获取节点的入度和出度
# - 出度: 从该节点出发的边的数量(包括所有多重边)
# - 入度: 指向该节点的边的数量(包括所有多重边)
print("节点度数:")
print(f"  节点 A: 出度={G.out_degree('A')}, 入度={G.in_degree('A')}")
print(f"  节点 B: 出度={G.out_degree('B')}, 入度={G.in_degree('B')}")
print(f"  节点 C: 出度={G.out_degree('C')}, 入度={G.in_degree('C')}")

可视化

networkx 可以与 matplotlib 结合来可视化图,对于 MultiDiGraph,可视化时所有边都会被画出。

Python中MultiDigraph如何高效处理多边有向图?-图2
(图片来源网络,侵删)
# 使用 matplotlib 绘制图形
plt.figure(figsize=(8, 6))
pos = nx.spring_layout(G, seed=42)  # 为节点设置一个固定的布局,使每次运行结果一致
# 绘制节点
nx.draw_networkx_nodes(G, pos, node_size=700, node_color='skyblue')
# 绘制边
# 由于边有方向,我们使用箭头
nx.draw_networkx_edges(G, pos, edge_color='gray', 
                       arrowstyle='->', arrowsize=20,
                       connectionstyle='arc3,rad=0.1') # 使用弧形让重叠的边更清晰
# 绘制节点标签
nx.draw_networkx_labels(G, pos, font_size=12, font_family='sans-serif')
# 绘制边标签(显示边的权重)
edge_labels = nx.get_edge_attributes(G, 'label')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels)
"MultiDiGraph 示例")
plt.axis('off') # 关闭坐标轴
plt.show()

运行上面的代码,你会看到一个图形,其中从 A 到 B 有两条线,从 B 到 C 有两条线,直观地展示了“多重”的概念。


MultiDiGraph vs. 其他图类型

图类型 有向? 多重边? 何时使用
Graph 最简单的图,用于无向、无重复连接的关系,如社交好友网络(无向)、分子结构(单键)。
DiGraph 有向图,用于有方向、但两点间最多只有一条连接的关系,如网页链接(有向)、单向关注关系。
MultiGraph 无向多重图,用于无向、但可有多条连接的关系,如两个城市间的多条公路。
MultiDiGraph 有向多重图,用于最复杂的关系,即有方向且可有多条连接,如本文所述的交通、工作流等场景。

MultiDiGraphnetworkx 库中一个功能强大的数据结构,专门用于表示和处理有向多重图,当你需要建模的系统或数据集具有以下特征时,它就是理想的选择:

  • 关系有方向性(A 影响 B,但 B 不一定影响 A)。
  • 节点对之间可以存在多个独立的关系(从 A 到 B 有三条不同的航线)。

通过为每条边添加属性字典,你可以进一步丰富模型的信息量,使其能够承载更复杂的业务逻辑和数据。

Python中MultiDigraph如何高效处理多边有向图?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇