P2-9.3 图如何表示关系?¶
Section ID:
P2-9.3Version:v2026.09.15
节点与边¶
NIST《算法与数据结构词典》将图描述为通过边连接的项集合,每项称为顶点或节点。
图用节点表示对象,用边表示对象之间的关系。
下图同时用图形与邻接表表示同一个图。
Kim、Lee、Park、Choi 是节点。
Kim -- Lee 这样的节点连线就是边。
同一关系也可写成每个节点的邻居列表。
| 节点 | 邻居列表 |
|---|---|
| Kim | Lee, Park |
| Lee | Kim, Park |
| Park | Kim, Lee, Choi |
| Choi | Park |
这就是邻接表表示:每个节点都保存与其连接的邻居列表。
关系行与邻居列表¶
相同朋友数据也可存入表格,每一行记录一条关系。
| person | friend |
|---|---|
| Kim | Lee |
| Kim | Park |
| Lee | Park |
| Park | Choi |
“谁与 Kim 相连?”或“能否经 Park 到达 Choi?”等沿连接查询的问题,更适合图的视角。
下图比较同一关系记录作为表和图时,关注的问题如何变化。
要从图的视角读取表格,可以按节点将关系行重新组成邻居列表。
使用 NetworkX 查询邻居¶
NetworkX 是构建图、查询邻居和路径的 Python 库。代码输入上述四条朋友关系和三条页面链接。Kim 的直接邻居为 Lee、Park,Choi 的最短距离为两步。页面链接中,page_b 指向 page_c,但没有反向链接。
预期输出:
nx.Graph() 创建朋友关系这样的无向连接,nx.DiGraph() 创建网页链接这样的有向连接。neighbors() 查询直接邻居,single_source_shortest_path_length() 计算从起点出发的步数。这里 weight 是示例关系强度,步数函数不使用它,每条边计一步。
树与环¶
树是图的一种特殊形式,NIST 的图定义也提到这一关系。
这里按以下方式区分。
无向树是连通且无环的图。指定根后,就能按父子层级读取。
书籍目录通常适合用树来理解。
人与人的关系则较难整理成树。
这些朋友关系包含 Kim → Lee → Park → Kim 这样的环,会回到同一节点,因此不是树。
连接的方向¶
图的边可以无向,也可以有向。
关系在两个方向具有相同含义时,使用无向图。
简化的朋友关系可写成 Kim -- Lee:Kim 是 Lee 的朋友,也意味着 Lee 是 Kim 的朋友。
无向图中的同一连接应能从两端节点读取。
| 节点 | 邻居 |
|---|---|
| Kim | Lee |
| Lee | Kim |
关系的方向重要时,使用有向图。
网页链接有方向。文档 A 链接到 B,并不意味着 B 也链接到 A。
有向图中记录连接所指向的节点。
| 起点 | 指向的节点 |
|---|---|
| page_a | page_b, page_c |
| page_b | page_c |
| page_c | 无 |
AI 与搜索中,方向往往很重要。例如文档引用另一文档、工作流进入下一步、用户点击物品,都可用有向图表示。
下图显示方向与权重如何改变边的含义。
不要假定有向关系也存在反向连接,应只按已记录的方向读取。
| 问题 | 回答 |
|---|---|
page_b 指向哪个页面? | page_c |
page_c 是否反向指向 page_b? | 在此表中没有 |
本例给出 page_b 到 page_c 的链接,没有给出反向链接。
权重的含义¶
连接的强度不一定相同。有些关系近,有些远,有些成本高。
附加在边上的数值称为权重。
假设 A、B、C 之间具有以下移动成本。这些是比较用数值,不是真实地理距离。
| 起点 | 终点 | 权重 |
|---|---|---|
| A | B | 160 |
| A | C | 325 |
| B | C | 200 |
A 直接到 C 成本为 325,经 B 则为 160 + 200 = 360。最小化成本会选择直连;将 A–C 改为 400 后,经 B 更便宜。
如果权重表示相似度,值越大可能表示关系越近。较大还是较小更好,取决于数值含义。
权重让问题不只停留在是否相连,还能询问有多近、成本多大或关联多强。
搜索或推荐候选的关系分数也适用同一视角。下面将已经计算好的关系分数与阈值比较。
| 候选文档 | 与查询的关系分数 | 与 0.7 比较 | 解读 |
|---|---|---|---|
doc_a | 0.91 | 不低于阈值 | 优先检查的强候选 |
doc_b | 0.72 | 不低于阈值 | 一同检查的候选 |
doc_c | 0.18 | 低于阈值 | 当前标准下暂缓的候选 |
将阈值提高到 0.8,doc_b 的 0.72 不再通过,只剩 doc_a。关系分数用于选择候选,并不保证文档内容准确。
更少步数与更低成本¶
最短路径的选择取决于距离是边数还是总成本。下面验证前面 A–C 成本改为 400 的情况。
输出为 ['A', 'C']、['A', 'B', 'C']、360。不指定权重时选择一步直连;weight="cost" 累加边成本,选择更便宜的路线。把直连成本降至 325 后,成本计算也返回直连路径和 325。
直接把相似度当成本,可能偏向相似度较小的路径。算法不会自行判断数值表示相似度还是移动成本,应先确定要最小化什么。
直接邻居与两跳邻居¶
从 Kim 出发,按最短路径上的边数计距离。直接邻居与最短距离为两步的节点如下。
| 标准 | 节点 | 解读 |
|---|---|---|
| 直接邻居 | Lee、Park | 与 Kim 直接连接 |
| 两跳候选 | Choi | Kim → Park → Choi,最短距离为 2 |
下图区分 Kim 的直接邻居与两跳邻居。
Lee 也能经 Kim → Park → Lee 两步到达,但直连使其最短距离为 1,因此不包含在代码的两跳邻居中。
AI 中的关系表示¶
| 场景 | 图的视角 |
|---|---|
| 知识图谱 | 概念、人物、地点、事件为节点,关系为边 |
| 推荐系统 | 用户与物品、物品与物品的连接 |
| 搜索 | 文档、链接、关键词、来源之间的连接 |
| RAG | 片段、元数据、来源与问题的关系 |
| 工作流 | 任务与后续步骤的连接 |
案例:增加一条朋友关系¶
在 NetworkX 示例中增加 Kim–Choi 直连。在 friend_graph.add_edges_from(friend_relationships) 后插入 friend_graph.add_edge("Kim", "Choi", weight=0.6) 并重新运行。
Kim 的直接邻居变为 ['Choi', 'Lee', 'Park'],两跳列表变为 [],因为 Choi 的最短距离从 2 降为 1。强度 0.6 不参与此次步数计算。
去掉新增行,再从输入中删除 ("Park", "Choi", {"weight": 0.7})。Choi 从输入边中消失;代码按边创建节点,因此节点列表变为 ['Kim', 'Lee', 'Park']。若要保留孤立的 Choi,应在创建图后显式调用 friend_graph.add_node("Choi")。这样 Choi 存在,但从 Kim 无法到达。
改变图中节点位置不同于增删边。只移动位置而保留连接,邻居与路径不会改变。
再次输入同一连接¶
nx.Graph() 不会在同一对节点间累计多条边。调用 friend_graph.add_edge("Kim", "Park", weight=0.5),原权重从 0.9 变为 0.5,边数不增加。要分别保留点击或交易事件,需要事件表或支持多重边的结构。
孤立节点存在与节点不存在不同。显式添加的孤立 Choi 不会出现在 Kim 的可达距离结果中,这不表示距离为 0:0 表示起点本身,无路径是另一种状态。
检查清单¶
- 能用节点与边解释图。
- 能将邻接表解释为每个节点的邻居列表。
- 能说明表与图强调的不同问题。
- 能初步解释树是图的特殊形式。
- 能区分无向图与有向图。
- 能解释权重为关系附加数值信息。
- 能用邻居列表表示小型图并沿连接移动。
- 能读懂 NetworkX 如何处理节点、边、邻居、方向与权重。
- 能识别连接关系重要的数据,并采用图视角。
- 能区分最少步数与最低成本路径,以及边的更新与新连接的添加。
来源与参考资料¶
- Paul E. Black and Paul J. Tanenbaum, graph, Dictionary of Algorithms and Data Structures, NIST,确认日期:2026-07-20。作为把 graph 说明为由 vertices/nodes 与 edges/arcs 构成的结构的依据。
- NetworkX Developers, Graph - Undirected graphs with self loops, NetworkX 3.6.1 documentation,确认日期:2026-07-20。用于从 Python 代码视角确认小型无向图、nodes、edges 和 adjacency relations。
- NetworkX Developers, DiGraph - Directed graphs with self loops, NetworkX 3.6.1 documentation,确认日期:2026-07-20。用于确认 directed graphs 和 successor relationships。
- NetworkX Developers, shortest_path, 核对日期:2026-09-15。用于区分无权最短路径与成本总和最小的路径。
- NetworkX Developers, Graph.add_edge, 核对日期:2026-09-15。确认重复添加已有边会更新其属性。