本章涵盖以下内容:
- 构建并整合复杂知识图谱
- 探索知识图谱示例
- 理解分析与查询技术
- 使用 LLM 分析 KG 结果
本章将进一步加深我们对如何构建规模更大、结构更复杂的知识图谱(KG)的理解,并探讨如何利用它们开发智能顾问系统(IAS)。在第 3 章中,我们只有一个以本体形式存在的知识库;从这一章开始,我们将从多个已经以图友好格式存在的结构化数据源中创建 KG。这样做可以让我们把重点放在图建模决策、整合策略和分析方法上。
注意
本书网站中的附录 C 提供了全面指导,介绍如何从多个复杂来源导入并转换原始数据。
接下来各节中的示例将涵盖:如何把结构化与半结构化模式和数据格式转换为同构图;如何对名称与标识符进行协调和匹配;如何使用后处理技术合并实体与关系;以及如何分析最终得到的 KG,以发现相关信息。虽然我们使用的是生物医学数据源,但其中的方法与模式可直接迁移到其他领域。
在 KG 生命周期的这一阶段,LLM 扮演的是互补性但相对有限的角色。本章中的数据源具有高度结构化特征(如 CSV 文件、关系型数据库和 API),因此传统的数据整合技术仍然是构建流程的主要手段,而 LLM 更适合作为辅助工具,而不是构建流水线中的核心组件。
4.1 生物医学知识图谱与应用
设想你被要求处理以下某种情形:
- 从疾病与蛋白质之间已知的关系出发,我们能否发现新的连接?
- 在不进行昂贵体外实验的前提下,我们能否发现 micro-RNA 与疾病之间有意义的关系?
- 乳糜泻(或其他疾病)涉及哪些关键过程?
- 是否有可能在不经历多年研究的情况下,对已有药物进行再利用?
- 我们如何支持精准医学,即利用患者特异性信息?
所有这些任务,都可以通过把现有生物医学知识组织为图,并判断图中是否包含足以回答复杂问题的知识来加以解决。
我们先限定一下本章示例领域的上下文。生物医学科学研究人体器官与系统,重点关注疾病、基因表达、蛋白质、药物及其相关主题。正如 Nicholson 和 Green [1] 所指出的,KG 可以帮助研究人员处理多种生物医学问题,例如为已有药物寻找新用途 [2]、辅助患者诊断 [3]、识别疾病与生物分子之间的关联 [4]、识别蛋白质功能 [5]、对癌症基因进行优先级排序 [6],以及为患者推荐更安全的药物 [7, 8]。每一种应用都有不同的业务目标,并且根据我们的 CRISP-DM 模型,也会使用不同的数据源来构建。
针对每一类应用,我们都会给出一个案例研究:展示如何导入并整合源数据库,然后对生成的图进行查询与分析。这个练习将帮助你学会如何选择数据源来构建 KG,以及如何判断这些信息是否足以完成预期任务。图 4.1 总结了不同类型的应用,以及其中最关键的节点与关系所承载的信息。
图 4.1 生物医学 KG 的主要应用类型,按业务目标分组。它们在数据源上有大量重叠。
4.2 KG 的多组学应用
多组学(multi-omic) 指的是一种生物学分析方法,它会同时使用多种 “omics” 数据集,例如基因组(genome)、蛋白质组(proteome)和转录组(transcriptome)(见图 4.2)。“ome” 这个后缀在分子生物学中表示“整体性(totality)”:例如,genome 指的是一个生物体全部的遗传信息。
图 4.2 生物医学 KG 中使用的三类主要 “omics” 数据:基因组(DNA)、转录组(RNA)和蛋白质组(蛋白质)数据。它们通过转录与翻译在生物学上彼此连接。
基因组、转录组与蛋白质组
以下术语及其相关概念将在本章中反复出现:
- Genome(基因组) ——一个生物体全部遗传信息的总和。大多数基因组由 DNA(脱氧核糖核酸)构成,但少数病毒拥有 RNA(核糖核酸)基因组。DNA 和 RNA 都是聚合分子,由称为核苷酸(nucleotides)的单体亚基链组成。
- Transcriptome(转录组) ——一组指导蛋白质组合成的 RNA 分子。转录组是通过“转录(transcription)”过程构建的,也就是把单个基因拷贝成 RNA 分子。
- Proteome(蛋白质组) ——基因组表达的最终产物,包含某个活细胞合成的全部功能性蛋白质。它既是基因组表达的结果,也是构成细胞生命活动的生化过程的起点。
许多多组学应用都使用 KG 来研究基因组、基因在转录组中的表达方式,以及这些转录产物在蛋白质组中的相互作用。这类应用包括识别 miRNA–疾病关联 [4]、基因–症状优先级排序 [9],以及蛋白质–蛋白质相互作用预测 [10, 11, 12]。
例如,Yang 等人 [9] 提出了一种 KG 模型,用于识别与给定症状相关的候选基因。研究人员整合了多个异构数据源。为了统一并整合疾病术语,他们把不同数据库中的疾病标识符映射为 统一医学语言系统(UMLS) (www.nlm.nih.gov/research/um…)代码。图 4.3 展示了这一过程。
图 4.3 引自 Yang 等人 [9] 图片中的一部分,展示了研究人员如何整合多个数据源,以创建一个整体性的 KG。
另一个案例中,蛋白质–蛋白质相互作用(PPI)网络与蛋白质–疾病关联,已经被成功用于计算式疾病通路发现(即与特定疾病相关的一组蛋白质)[12]。这正是一个开发 IAS 的理想用例,而 KG 在其中扮演关键角色,因为如果只孤立地理解每一种疾病蛋白,就无法完整解释大多数人类疾病。接下来,我们将先看如何构建并分析这种相对简单的 KG,再进入那些需要合并多个数据源的更复杂场景。
4.2.1 从 PPI 网络与蛋白质–疾病网络创建 KG
我们的目标,是从已知通路出发发现疾病通路。Agrawal 等人 [12] 提出的方法,是从一个 KG 开始,如图 4.4 所示。疾病连接到与之相关的已知蛋白质,而这些蛋白质又连接在 PPI 网络中。例如,图 4.5 展示了乳糜泻(celiac disease)与相关基因之间的连接关系。
图 4.4 疾病通路是 PPI 网络中的一个子图,由一组与该疾病相关的蛋白质所定义。
图 4.5 Agrawal [12] 构建的 KG 中的一小部分。我们从乳糜泻出发,找到了与其相关的基因。
现在我们来看一下这个发现过程,以理解我们接下来将如何使用这个简单 KG。图 4.6 展示了起点与结果:我们有一组已知通路,而 IAS 的任务是预测并给出一组与该疾病相关的潜在蛋白质及相关通路。这些蛋白质可能属于已有通路,也可能形成新的通路。最终得到的 KG 由一个单分图(monopartite graph) ——即 PPI 网络——以及一个二分图(bipartite graph) ——即疾病–蛋白质关联网络——共同组成。
在这个例子中,我们已经具备所需数据源:可以使用来自 Stanford Network Analytics Project(SNAP;snap.stanford.edu/pathways/)的 Disease Pathways in the Human Interactome 数据集。Agrawal [12] 是从更复杂的数据源构建出这一较简化网络的,而我们可以直接导入并探索它。随后,我们还会将其与另一个数据集结合,以使最终 KG 更便于人类阅读。
图 4.6 发现与疾病相关蛋白质的过程
下面的节点键约束(node key constraints)保证:具有特定标签的所有节点都必须拥有一个 ID 值,并且该值必须唯一。
清单 4.1 创建约束
CREATE CONSTRAINT protein_key IF NOT EXISTS FOR #1
(n:Protein) REQUIRE (n.id) IS NODE KEY; #1
CREATE CONSTRAINT disease_key IF NOT EXISTS FOR #1
(n:Disease) REQUIRE (n.id) IS NODE KEY; #1
- #1 如果你不确定某个约束是否已经存在,可以加上
IF NOT EXISTS,以确保只有在它不存在时才会创建。
我们将导入到数据集中的第一个文件,是由 Menche 等人 [13] 和 Chatr-Aryamontri 等人 [14] 汇编的人类蛋白质–蛋白质相互作用(PPI)网络。这个图包含 342,354 条经实验记录的人类蛋白质相互作用,覆盖 21,559 个蛋白质。清单 4.2–4.4 假设这些文件已经从 SNAP 下载、解压,并被移动到了 Neo4j import 目录下的 PPI 子目录中。
清单 4.2 导入 PPI 网络
:auto LOAD CSV FROM 'file:///PPI/bio-pathways-network.csv' AS line
CALL {
WITH line
MERGE (f:Protein {id: trim(line[0])})
MERGE (s:Protein {id: trim(line[1])})
MERGE (f)-[:INTERACTS_WITH]->(s)
} IN TRANSACTIONS OF 100 ROWS
练习
运行必要的查询,验证蛋白质数量以及它们之间连接的数量。请务必在下一步之前完成,因为下一步会引入新的蛋白质。
接下来,我们将导入蛋白质–疾病关联,其形式是元组 (u, d),表示蛋白质 u 的改变与疾病 d 存在关联。这些关联来自 DisGeNET(www.disgenet.org),它是一个集中整合疾病知识的平台。它包含 21,000 多条蛋白质–疾病关联,覆盖 519 种疾病,而这些疾病中每种都至少关联 10 个疾病蛋白。
清单 4.3 导入疾病通路
:auto LOAD CSV WITH HEADERS
FROM 'file:///PPI/bio-pathways-associations.csv' AS line
CALL {
WITH line
WITH trim(line["Associated Gene IDs"]) AS proteins,
trim(line["Disease Name"]) AS diseaseName,
trim(line["Disease ID"]) AS diseaseId
MERGE (d:Disease {id: diseaseId, name: diseaseName})
WITH d, proteins
UNWIND split(proteins, ",") AS protein
WITH d, protein
MERGE (p:Protein {id: trim(protein)})
MERGE (d)-[:ASSOCIATED_WITH]->(p)
} IN TRANSACTIONS OF 100 ROWS
练习
做一些检查来验证数量。你应该会注意到蛋白质总数发生了变化。你能找出新增的蛋白质吗?提示:使用 NOT EXISTS 子句。
从 SNAP 数据集中下载的最后一个文件包含疾病类别。疾病通过 Disease Ontology(disease-ontology.org/)被划分为类别和子类别,并映射到 UMLS 代码。在从 DisGeNET 提取的 519 种疾病中,有 290 种疾病具有可映射到该本体中代码的 UMLS 编码。该数据集使用了本体的第二层级,共包含 10 个类别,例如癌症(68 种疾病)、神经系统疾病(44 种)、心血管系统疾病(33 种)和免疫系统疾病(21 种)。
清单 4.4 导入疾病类别
:auto LOAD CSV WITH HEADERS
↪FROM 'file:///PPI/bio-pathways-diseaseclasses.csv' AS line
CALL {
WITH line
WITH line["Disease ID"] as diseaseId, line["Disease Class"] as class
MATCH (d:Disease {id:diseaseId})
SET d.class = class
} IN TRANSACTIONS OF 100 ROWS
练习
导入完成后,请检查每一种疾病类别对应的数量,以及那些没有类别的疾病列表。
到这里,我们已经导入了 SNAP 数据集中的数据,但它使用代码来标识蛋白质。为了提高可读性,我们可以从 NIH 导入基因信息(ftp.ncbi.nih.gov/gene/DATA/g…)。下载文件后,将其解压并移动到与 PPI 数据相同的目录中。
清单 4.5 导入基因信息
:auto LOAD CSV WITH HEADERS FROM 'file:///PPI/gene_info' AS line FIELDTERMINATOR '\t'
CALL {
WITH line
WITH trim(line["GeneID"]) AS proteinId, trim(line["Symbol"]) AS symbol,
trim(line["description"]) AS description
WITH proteinId, symbol, description
MATCH (p:Protein {id:proteinId})
SET p.name = symbol, p.description = description
} IN TRANSACTIONS OF 100 ROWS
4.2.2 对生成的 KG 进行高层分析
下一步是检查 KG,以评估图的质量并探索数据库。如果你没有跟着前面的步骤操作,可以从 mng.bz/5v7O 下载一个 Neo4j 备份。下面的清单展示了如何在 Neo4j 5.x 中导入这个数据库。
清单 4.6 从 Neo4j 备份创建 PPI 数据库
# Add the following line to the neo4j.conf file
# dbms.databases.seed_from_uri_providers=URLConnectionSeedProvider
# then run the following command
CREATE DATABASE ppi OPTIONS { existingData: "use",
↪seedUri: "https://mng.bz/5v7O"}
我们对图的分析,首先从对 PPI 网络的整体评估开始。对于这种评估,我们最常用的算法是弱连通分量(weakly connected component, WCC) :一种社区发现算法,用于在图中识别彼此不连通的子图。为了运行这项分析,我们将使用 Neo4j 提供的 graph data science(GDS) 库(安装说明见在线附录 B)。
首先,我们用 INTERACTS_WITH 关系标记出 PPI 网络中的连通蛋白。
清单 4.7 标记 PPI 网络中的蛋白质
MATCH (p:Protein)-[:INTERACTS_WITH]-()
SET p:PPIProtein
接下来,我们需要创建这个图的内存表示,即所谓的图投影(projection) 。
清单 4.8 在内存中创建图投影
call gds.graph.project(
'ppi-graph', #1
'PPIProtein', #2
{
INTERACTS_WITH: { #3
orientation: 'UNDIRECTED'
}
}
)
- #1 内存图的名称
- #2 希望纳入分析的节点类型列表。在本例中只有一种,但也可以是一个列表。
- #3 希望纳入分析的关系类型列表。
在内存中创建出这个子图之后,我们就可以使用下面的查询运行 WCC 算法。
清单 4.9 在 PPI 网络上运行 WCC
CALL gds.wcc.write('ppi-graph', { writeProperty: 'componentId' })
YIELD nodePropertiesWritten, componentCount, componentDistribution;
这个查询的结果如表 4.1 所示。百分位数(percentiles)表示:有多少比例的数据点落在某个值以下。例如,p99: 21521 表示 99% 的连通分量所包含的蛋白质数量都少于 21,521。
表 4.1 清单 4.9 查询结果摘要
| nodePropertiesWritten | componentCount | componentDistribution |
|---|---|---|
| 21559 | 27 | { "p99": 21521, "min": 1, "max": 21521, "mean": 798.481, "p90": 3, "p50": 1, "p999": 21521, "p95": 4, "p75": 2 } |
算法输出显示:PPI 网络中的蛋白质高度连通。图中的 21,559 个蛋白质可以被划分为 27 个互不重叠的子图。其中一个子图非常大,包含 21,521 个蛋白质;其余子图则要么是单个节点,要么只是由最多四个节点组成的小“孤岛”。
WCC 仅仅因为蛋白质之间存在连接,就把它们划分到同一个组中。但在这些被划到同一组的蛋白质中,可能还存在“彼此之间连接更稠密、而与组外蛋白质连接更稀疏”的子群体。为了发现这种结构,我们可以使用另一种图聚类方法:Louvain 模块度算法(Louvain modularity algorithm) [15]。这是基于模块度的算法中速度最快的一类之一,非常适合大图。它能够揭示不同尺度上的社区层级,有助于理解网络的整体运行方式。它通过最大化每个社区的模块度分数来工作——也就是评估某一组节点相较于随机网络中应有的连接程度,其内部连接究竟密集了多少。
下面这个查询会在与前面相同的内存图上运行 GDS 中实现的 Louvain 算法。如果你重启过数据库,或者之前没有执行过投影,那么在运行这个查询之前,必须先执行清单 4.8。
清单 4.10 在 PPI 网络上运行 Louvain 算法
CALL gds.louvain.write('ppi-graph',
{ writeProperty: 'componentLouvainId' })
YIELD communityCount, modularity, modularities, communityDistribution
该算法的结果如表 4.2 所示,而它讲述的是一个与 WCC 不同的故事。
表 4.2 清单 4.10 查询结果摘要
| communityCount | modularity | communityDistribution |
|---|---|---|
| 48 | 0.5464241018027929 | { "p99": 3533, "min": 1, "max": 3533, "mean": 449.1458333333333, "p90": 1817, "p50": 3, "p999": 3533, "p95": 2336, "p75": 311 } |
我们可以看到,一些社区很大,包含 3,500 多个蛋白质;同时也存在许多较小社区。平均而言,每个社区约包含 450 个蛋白质。考虑到所有社区后,整体模块度分数大约为 0.40(40%)。接下来的查询允许我们检查这些社区内部的具体内容。
清单 4.11 检查前 10 个社区
MATCH (p:PPIProtein)
WITH p.componentLouvainId as communityId, count(p) as members
ORDER BY members desc
LIMIT 10
MATCH (p:PPIProtein)-[:INTERACTS_WITH]-(o)
WHERE p.componentLouvainId = communityId
WITH communityId, members, p.name as name, count(o) as connections
ORDER BY connections DESC
RETURN communityId, members, collect(name)[..20] as keyMembers
这个查询会返回由 Louvain 算法识别出的每个社区中,连接最密集的前 20 个元素。最大的那个聚类包含诸如 APP、NTRK1、GRB2、EGFR 和 HSP90AA1 这样的蛋白质;另一个聚类则包括 ELAVL1、MOV10、NXF1、VCP 和 SHMT2。稍微做一点检索(毕竟我们不是这方面专家)就会发现,这些分组是符合生物学意义的。
这些算法使用起来很方便,但它们是通用型的:它们把每个节点和每条关系都视为同等地位。接下来,我们将引入若干与本领域和目标强相关的技术方法,它们会利用每个节点和每条关系的具体含义。本书代码中已经包含了这些工具库。
4.2.3 面向领域的 PPI 与疾病 KG 分析
前面的算法分析的是 PPI 网络整体结构。现在我们转而关注其中的子网络(subnetworks) ,也就是疾病通路。用图论语言来说,给定 PPI 网络 ( G = (V, E) ),其中节点 ( V ) 表示蛋白质,边 ( E ) 表示蛋白质–蛋白质相互作用。那么,疾病 ( d ) 的疾病通路,就是 PPI 网络中的一个无向子图 ( H_d = (V_d, E_d) ):
其中 ( V_d ) 表示与疾病 ( d ) 相关的一组蛋白质,而 ( E_d ) 则表示这些蛋白质之间的相互作用集合。
利用我们的图,可以通过一个简单查询来提取这一子网络。
清单 4.12 从 KG 中提取疾病通路
MATCH (d:Disease {id:$id})-[:ASSOCIATED_WITH]->(p)
WITH collect(p) as proteins
UNWIND proteins as m0
UNWIND proteins as m1
OPTIONAL MATCH (m0)-[r:INTERACTS_WITH]->(m1)
RETURN DISTINCT m0, r, m1
这是一个单分图子网络(monopartite subnetwork) ,也就是说,它不包含蛋白质与疾病之间的连接。不同疾病对应的疾病通路也可能彼此重叠。
对于某些度量方法来说,我们还必须考虑这个子网络与整个 PPI 网络其余部分之间的连接方式。为此,我们可以计算通路边界(pathway boundary) :
其中 ( V \setminus V_d ) 表示所有属于全局节点集 ( V ) 但不属于 ( V_d ) 的节点,也就是所有不与目标疾病相关联的节点。
我们接下来考虑的这些度量,主要用于刻画疾病蛋白质的连通性:既包括它们在疾病通路内部的连接,也包括它们与 PPI 网络中其他蛋白质之间的外部连接。还有一些度量则关注通路中的距离与集中性。所有这些指标都会对每一种疾病分别计算,以便刻画每一种疾病并发现重要模式。它们也可以被统一收集,之后通过统计汇总来帮助我们从更宏观层面理解整个网络,以及它在不同疾病上的分布情况。
最大通路连通分量(Largest Pathway Component)
第一个度量,是最大通路连通分量的相对大小。这个度量计算的是:疾病通路 ( H_d ) 中,属于最大连通分量的疾病蛋白质所占的比例:
其中 nodes(largestCC(Hd)) 返回的是 ( H_d ) 中最大弱连通分量(WCC)所包含的节点。代码中使用的是 networkx 函数,见下一段代码(完整代码位于本书代码仓库中的 chapter/ch04/analysis/multiomic_analysis.py)。
清单 4.13 计算最大通路连通分量的大小
class MultiOmicAnalysis(GraphDBBase): #1
def __init__(self, argv, database):
super().__init__(command=__file__, argv=argv)
self.__database = database
def load_hd(self, disease): #2
query = """
MATCH (d:Disease {id:$id})-[:ASSOCIATED_WITH]->(p)
WITH collect(p) as proteins
UNWIND proteins as m0
UNWIND proteins as m1
OPTIONAL MATCH (m0)-[r:INTERACTS_WITH]->(m1)
return distinct m0, r, m1
"""
param = {"id": disease}
return self.load_graph_and_get_nx_graph(query, param)
def load_graph_and_get_nx_graph(self, query, param={}): #3
data = self.get_raw_data(query, param)
G = networkx_utility.graph_undirected_from_cypher(data) #4
return G
def get_raw_data(self, query, param): #5
with self._driver.session(database = self.__database) as session:
results = session.run(query, param)
return results.graph()
def compute_largest_components(self, networkx_graph): #6
largest_cc = max(nx.connected_components(networkx_graph), key=len)
return largest_cc
if __name__ == '__main__':
analysis = MultiOmicAnalysis(argv=sys.argv[1:], database="ppi")
disease_id = 'celiac disease' #7
networkx_graph = analysis.load_Hd(disease_id)
nodes_count = networkx_graph.nodes.__len__()
largest_cc = analysis.compute_largest_components(networkx_graph)
relative_size_of_largest_cc =
float(largest_cc_size.__len__())/nodes_count #8
- #1 一个用于分析 PPI 网络的 Python 类。它继承自一个基类,该基类包含命令行参数处理与 Neo4j 数据库连接等基本功能。
- #2 加载疾病通路,也就是 PPI 网络中的一个子图。
- #3 接收一个表示子图的查询,并将其加载为一个
networkx图。 - #4 把查询结果转换为
networkx图。 - #5 返回节点与关系列表,以供进一步处理。
- #6 计算所有连通分量,并返回其中最大的一个。
- #7 要分析的疾病(完整代码会分析所有疾病)。
- #8 计算最大连通分量的相对大小,并以节点总数做归一化。
密度(Density)
我们要计算的第二个指标是通路密度(density) 。顾名思义,它衡量的是疾病通路中的蛋白质彼此之间连接得有多紧密:
分母表示所有可能存在的边数,分子表示实际存在的边数。结果值落在 ([0, 1]) 之间:密度越高,说明 ( H_d ) 中节点之间出现的边,占所有可能边的比例越高。
清单 4.14 计算通路密度
def compute_density(networkx_graph): #1
nodes_count = networkx_graph.nodes.__len__()
edges_count = networkx_graph.edges.__len__()
density_pathway =
2.0 * float(edges_count) / (nodes_count * (nodes_count - 1))
if __name__ == '__main__':
analysis = MultiOmicAnalysis(argv=sys.argv[1:], database="ppi")
disease_id = 'celiac disease'
networkx_graph = analysis.load_hd(disease_id)
density_pathway = compute_density(networkx_graph)
- #1 针对某一疾病所对应的子图,计算其密度。
电导率(Conductance)
第三个指标是电导率(conductance) [16]:它表示疾病通路(即子图)相对于图其余部分的独立程度。这个指标使用的是那些“一个端点在子图内部、另一个端点在子图外部”的边,而不考虑边的方向:
结果同样落在 ([0, 1]) 范围内:电导率越低,说明该通路越像一个内部紧密、与外界较为隔离的社区。
清单 4.15 计算电导率
def compute_bd(self, disease): #1
query = """
MATCH (d:Disease {id:$id})-[:ASSOCIATED_WITH]->(p)
WITH collect(p) as proteins
MATCH (m0)-[r:INTERACTS_WITH]-(m1)
WHERE m0 in proteins and not m1 in proteins
RETURN count(DISTINCT r) as bd
"""
param = {'id': disease}
return self.get_data(query, param)["bd"][0]
def get_data(self, query, param={}): #2
with self._driver.session(database=self.__database) as session:
results = session.run(query, param)
data = pd.DataFrame(results.values(), columns=results.keys())
return data
if __name__ == '__main__':
analysis = MultiOmicAnalysis(argv=sys.argv[1:], database="ppi")
disease_id = 'celiac disease'
networkx_graph = analysis.load_hd(disease_id)
bd = analysis.compute_bd(disease_id)
edges_count = networkx_graph.edges.__len__()
conductance = float(bd) / (bd + 2 * edges_count) #3
- #1 通过 Cypher 查询计算 ( B_d )
- #2 返回一个 pandas DataFrame,其列表示查询返回的字段;当 Cypher 返回的是数值而非节点和关系时,这种方式特别有用。
- #3 计算电导率。
分析疾病通路与聚类结果
现在我们已经为每个子图——即疾病通路——计算出了这些指标,接下来就把它们放在整体层面来看。常见做法之一,是进行频率分析,把结果分桶统计,如图 4.7 所示。
图 4.7 疾病通路三个关键指标的分布
我们可以看到,在 PPI 网络中,疾病通路是高度碎片化的:每种疾病的连通分量中位数为 16,而最大通路连通分量中蛋白质所占比例的中位数只有 21%(图 4.7a)。只有大约 10% 的通路,其最大连通分量中包含了超过 60% 的蛋白质。疾病通路在内部连接上并不紧密,中位密度仅为 0.07(相比之下,整个 PPI 网络的总体密度是 0.0015),而 90% 的疾病通路密度都低于 0.17(图 4.7b)。另一方面,疾病通路在外部连接上却非常强,其中位电导率高达 0.96(图 4.7c)。
这些通过疾病通路得到的重叠子图,与使用 WCC 或 Louvain 得到的聚类结果有很大不同。为了验证这一点,我们可以把同样的指标应用到通过 Louvain 计算出的聚类结果上,其结果如图 4.8 所示。
图 4.8 使用 Louvain 算法得到的聚类,在三个关键指标上的分布
这些聚类展示了一个完全不同的故事。正如预期,大多数蛋白质都落在一个大的连通分量中(图 4.8a)。密度与网络整体连通性有关,因此其变化主要源于聚类结构本身的不同。电导率则有所改善:这些聚类在内部比在外部连接得更紧密。
下一节将介绍第二类应用(制药领域),并引入用于从 KG 中提取信息的新算法。除了单个节点之外,我们将重点关注边和路径。
4.3 KG 在制药领域的应用
一个新的治疗药物的开发成本,据估计高达 14 亿美元 [17]。从最初发现化合物到真正推向市场,这一过程通常需要 15 年 [18],而成功率却低得惊人 [19]。
药物分析与药物再利用(repurposing)能够大幅缩短审批周期、降低失败率,并压缩成本。这类分析会利用关于已获批药物的既有信息,包括毒理学分析、临床前模型、临床试验以及上市后的持续监测。已有大量例子表明,KG 已被用于预测药物相互作用 [20]、识别药物可能作用的分子靶点 [21],以及判断已知药物是否还能治疗新的疾病 [22]。
Dai 等人 [21] 使用推荐系统,特别是协同过滤(collaborative filtering),来推断药物–疾病关联。其他研究者也使用类似技术推断药物–靶点相互作用 [23, 24] 以及药物–疾病治疗关系 [25, 26]。尽管这些方法已取得成功,但它们仍然受限于图中已有的药物和疾病。如果我们通过加入化学结构、生物过程及其他相关知识来丰富 KG,那么就有可能进一步支持研究人员对新化合物进行预测。
Himmelstein 等人 [2] 构建了一个图,整合来自 29 个公共资源的知识,把化合物、疾病、基因、解剖结构、通路、生物过程、分子功能、细胞组分、药理类别、副作用和症状连接起来。他们把这个图称为 Hetionet(来源于 “hetnet”,即 heterogeneous network,异构网络)。该图数据库已经以 Neo4j 格式公开发布(het.io/)。因此,在这个例子中,我们不需要自己从多个数据源搭建数据库,因为研究者已经替我们完成了这项工作。我们将重点讨论:一个设计良好、模式一致的 KG 为什么重要,以及如何分析它来评估其中信息的完整性。
我们已经为该数据库准备好了一个 Neo4j 5.x 的备份,你可以从 mng.bz/648e 下载。下面的清单展示了如何导入它。
清单 4.16 创建 Het.io 数据库
# Add the following line to the neo4j.conf file
# dbms.databases.seed_from_uri_providers=URLConnectionSeedProvider
# then run the following command
CREATE DATABASE hetionet OPTIONS { existingData: "use",
↪seedUri: "https://mng.bz/648e"}
导入后的 KG 包含 47,031 个节点,分为 11 种类型,以及 2,250,197 条关系,分为 24 种类型。其中节点包括 1,552 个小分子化合物和 137 种复杂疾病,还包括基因、解剖结构、通路、生物过程、分子功能、细胞组分、扰动、药理类别、药物副作用和疾病症状。边则表示这些节点之间的关系,承载的是过去半个世纪数百万项研究所共同产生的知识 [2]。图 4.9 展示了该数据集的完整模式。
例如,Compound–binds–Gene 类型的边表示:某种化合物会与由某个基因编码的蛋白质发生结合。Hetionet 中包含 11,571 条这样的边,并且每条边都把参考文献存储为关系属性。
练习
探索导入后的图,并检查不同节点类型上的节点分布。对关系也做同样的检查。注意:关系的情况可能会更复杂。请参考模式图,编写准确的查询。
图 4.9 Het.io KG 的模式。节点与关系的详细信息见 mng.bz/EwgD。
元路径与度加权路径计数(DWPC)
接下来关于路径探索的示例,将使用一个新的相关性排序指标:degree-weighted path count(DWPC) ,即“度加权路径计数”。它由 Himmelstein [27] 提出,改造自一个最初为社交网络分析而开发的方法,名为 PathPredict [28]。DWPC 用来量化 Hetionet 中元路径(metapath)的出现强度。
如下一幅图的 (a) 所示,一个模式图(schema)由真实节点与现有关系表示。而一个元路径(metapath) ,则是对“节点类型序列 + 关系类型序列”的描述,用来表示某种潜在的真实路径——从一种类型的起点节点,到另一种类型的终点节点。我们可以对模式图进行“查询”,搜索源类型与目标类型之间的连接模式。例如,对于一个泛化模式 (Gene)—a—(Disease),并限制最大长度为 4,我们就可以枚举出一组可能的元路径,如图的 (b) 所示。
Hetionet 的模式图(a)与元路径(b)示意。模式图描述数据库结构,说明节点类型与关系类型;元路径描述的是路径模式,标明其中的节点类型与关系类型。
再次强调:这些只是对路径的描述,而不是路径的真实实例。
既然已经探索了这个示例 KG,我们就可以开始计算指标。最简单的元路径指标是 path count(PC) :也就是在给定起始节点与目标节点之间,某一指定元路径的实例路径数。PC 不会对路径经过节点的连通程度进行调整:每一条路径的贡献值都等于 1。比如,图 4.10a 展示了 KG 的一部分,其中某个特定基因 IRF1 与某个特定疾病 multiple sclerosis(多发性硬化) 存在联系。所有这些路径都属于泛化模式 (Gene)—a—(Disease) 下某一种可能的元路径。在图 4.10b 中,不同元路径对应的路径被分组展示。第一组中,路径的中间节点类型是 Tissue,并且只有一条路径,因此 PC 为 1。第二组中,中间节点类型是另一个基因;在这一组里,图中有三条路径,因此 PC 为 3。
图 4.10 (a)基于指定元路径提取路径,以及(b)计算路径度乘积(PDP)和 DWPC
另一方面,DWPC 会为每一条具体路径赋予一个单独的数值,这个值叫做 path-degree product(PDP) ,即“路径度乘积”。它按如下公式计算:
具体步骤如下:
- 提取该路径上每条边对应的、与元边类型相关的度值集合 ( D_{path} ),路径中的每一条边都要贡献两个度值。
例如在图 4.10 中,IRF1 与 IL2RA 之间那条边对应的两个度值分别为 4 和 1:IRF1 有 4 条类型为INTERACTS的出边,而 IL2RA 有 1 条类型为INTERACTS的入边。IRF1 与 CXCR4 之间那条边的度值则是 4 和 2,因为 CXCR4 有 2 条INTERACTS入边。 - 把每个度值提升到 (-w) 次幂,其中 ( w \ge 0 ),称为阻尼指数(damping exponent) 。
- 将所有经幂运算后的度值相乘,得到 PDP。
来看图 4.10 中这条路径:(IRF1)—[]—(CXCR4)—[]—(Multiple sclerosis)。假设 ( w = 0.5 ),那么计算过程如下:
图 4.10 中还展示了其他路径的数值。对于某一特定元路径而言,它的 DWPC 就等于该元路径下所有路径 PDP 的总和:
这些指标既衡量了路径的普遍性,同时又避免了被“众所周知的高连接节点”主导——这是 KG 分析中一个非常常见的问题。
4.3.1 对 Hetionet 知识图谱进行深度分析
到这里,我们已经具备了对 Hetionet 图进行深度分析的全部要素。我们将使用 Cypher 查询与 DWPC 指标,识别某组疾病相关基因中最突出的基因本体(GO)生物过程。
注意
下面这段分析的灵感来自 Daniel Himmelstein 发起的 Thinklab 项目(think-lab.github.io/d/220/)。
我们仍以**乳糜泻(celiac disease, CD)**为例。CD 是一种常见(患病率约 1:100)、慢性、由免疫介导的肠病,由麸质不耐受引发,并发生在具有遗传易感性的个体中。我们可以通过以下查询查看与 CD 相关的 48 个基因:
MATCH p = (:Disease {name: 'celiac disease'})-[rel: ASSOCIATES_DaG]-() RETURN p
接下来,我们将计算:在至少有两个与乳糜泻相关基因参与的情况下,CD 与每一个 GO 过程之间的 DWPC。结果还会进一步限制,只保留那些至少有 5 个参与基因的过程。Cypher 查询如下。
清单 4.17 针对乳糜泻的 GO 过程富集分析
MATCH path = (n0:Disease)-[:ASSOCIATES_DaG]-(n1)-[:PARTICIPATES_GpBP]-
↪(n2:BiologicalProcess) #1
WHERE n0.name = 'celiac disease' #2
WITH
[ size([(n0)-[:ASSOCIATES_DaG]-() | n0]),
size([()-[:ASSOCIATES_DaG]-(n1) | n1]),
size([(n1)-[:PARTICIPATES_GpBP]-() | n1]),
size([()-[:PARTICIPATES_GpBP]-(n2) | n2])
] #3
AS degrees, path, n2
WITH
n2.identifier AS go_id, #4
n2.name AS go_name, #4
count(path) AS PC, #5
sum(reduce(pdp = 1.0, d in degrees| pdp * d ^ -0.4)) AS DWPC, #6
size([(n2)-[:PARTICIPATES_GpBP]-() | n2]) AS n_genes #7
WHERE n_genes >= 5 AND PC >= 2 #8
RETURN
go_id, go_name, PC, DWPC, n_genes
ORDER BY DWPC DESC
LIMIT 10
- #1 查找 DaG-GpBP 路径
- #2 将源节点限制为
'celiac disease' - #3 计算 DWPC 所需的、与关系相关的度值
- #4 返回 GO 过程的 ID 和名称
- #5 统计路径数
- #6 计算 DWPC
- #7 统计该 GO 过程中的基因数
- #8 过滤掉“基因数少于 5”或“乳糜泻相关基因少于 2”的 GO 过程
我们运行该查询后,得到表 4.3 中列出的前 10 个 GO 过程。
表 4.3 清单 4.17 查询结果
| GO ID | GO name | PC | DWPC | # genes |
|---|---|---|---|---|
| GO:0031295 | T cell costimulation | 10 | 0.03347 | 75 |
| GO:0031294 | lymphocyte costimulation | 10 | 0.03329 | 76 |
| GO:0002507 | tolerance induction | 3 | 0.03276 | 12 |
| GO:0050870 | positive regulation of T cell activation | 14 | 0.02925 | 201 |
| GO:0034112 | positive regulation of homotypic cell-cell adhesion | 14 | 0.02902 | 205 |
| GO:1903039 | positive regulation of leukocyte cell-cell adhesion | 14 | 0.02891 | 207 |
| GO:0051249 | regulation of lymphocyte activation | 18 | 0.02763 | 381 |
| GO:0002684 | positive regulation of the immune system process | 21 | 0.02718 | 880 |
| GO:0022409 | positive regulation of cell-cell adhesion | 14 | 0.02716 | 242 |
| GO:0050863 | regulation of T cell activation | 16 | 0.02701 | 290 |
ID 为 GO:0002684 的 GO 过程具有很高的 PC 值,并且与 880 个基因相连。如果按 PC 排序,它会排在第一位。然而,这个过程参与了大量其他过程,而不仅仅是与 CD 相关;因此如果按 DWPC 排序,它反而落到了结果列表靠后的位置。排在最前的是 GO:0031295——“T cell costimulation”,这个过程与我们当前研究的疾病高度相关。
现在,我们通过引入更复杂的路径(包括蛋白质相互作用关系)来进一步细化搜索。下一段清单中的查询,只考虑那些来自全基因组关联研究(GWAS) [29, 30] 的疾病–基因关联,因为这种关联比起已有知识更少偏倚。我们还在元路径中加入蛋白质相互作用,以识别 CD 在相互作用组(interactome)邻域中的基因。最后,查询只考虑那些在乳糜泻受影响组织中被**上调(upregulated)**的基因。
清单 4.18 面向组织特异性的相互作用组分析
MATCH path = (n0:Disease)-[e1:ASSOCIATES_DaG]-(n1)-[:INTERACTS_GiG]-(n2)-
↪[:PARTICIPATES_GpBP]-(n3:BiologicalProcess)
WHERE n0.name = 'celiac disease'
AND 'GWAS Catalog' in e1.sources
AND exists((n0)-[:LOCALIZES_DlA]-()-[:UPREGULATES_AuG]-(n2))
WITH
[ size([(n0)-[:ASSOCIATES_DaG]-() | n0]),
size([()-[:ASSOCIATES_DaG]-(n1) | n1]),
size([(n1)-[:INTERACTS_GiG]-() | n1]),
size([()-[:INTERACTS_GiG]-(n2) | n2]),
size([(n2)-[:PARTICIPATES_GpBP]-() | n2]),
size([()-[:PARTICIPATES_GpBP]-(n3) | n3])
] AS degrees, path, n3 as target
WITH
target.identifier AS go_id,
target.name AS go_name,
count(path) AS PC,
sum(reduce(pdp = 1.0, d in degrees| pdp * d ^ -0.4)) AS DWPC,
size([(target)-[:PARTICIPATES_GpBP]-() | target]) AS n_genes
WHERE 5 <= n_genes <= 100 AND PC >= 2
RETURN
go_id, go_name, PC, DWPC, n_genes
ORDER BY DWPC DESC
LIMIT 10
查询结果见表 4.4。
表 4.4 清单 4.18 查询结果
| GO ID | GO name | PC | DWPC | # genes |
|---|---|---|---|---|
| GO:0031295 | T cell costimulation | 10 | 0.00665 | 75 |
| GO:0031294 | lymphocyte costimulation | 10 | 0.00662 | 76 |
| GO:0010560 | positive regulation of glycoprotein biosynthetic process | 6 | 0.00342 | 17 |
| GO:0033689 | negative regulation of osteoblast proliferation | 4 | 0.00341 | 9 |
| GO:1903020 | positive regulation of glycoprotein metabolic process | 6 | 0.00327 | 19 |
| GO:0006573 | valine metabolic process | 5 | 0.00277 | 8 |
| GO:0070884 | regulation of calcineurin-NFAT signaling cascade | 2 | 0.00277 | 19 |
| GO:0010559 | regulation of glycoprotein biosynthetic process | 7 | 0.00272 | 35 |
| GO:1903018 | regulation of glycoprotein metabolic process | 7 | 0.00257 | 40 |
| GO:0070098 | chemokine-mediated signaling pathway | 9 | 0.00256 | 72 |
这些结果更加具体。排在前两位的仍是之前那两个过程,但加入蛋白质相互作用后,返回了其他疾病特异性的特征,例如与糖蛋白相关过程的显著占优。如果我们对“positive regulation of glycoprotein biosynthetic process”这一关系特别感兴趣,还可以进一步检索组成其 DWPC 的具体路径。
清单 4.19 查找构成某个 DWPC 的路径
MATCH path = (n0:Disease)-[e1:ASSOCIATES_DaG]-(n1)-[:INTERACTS_GiG]-(n2)-
↪[:PARTICIPATES_GpBP]-(n3:BiologicalProcess)
WHERE n0.name = 'celiac disease'
AND n3.name = 'positive regulation of glycoprotein biosynthetic process'
AND 'GWAS Catalog' in e1.sources
AND exists((n0)-[:LOCALIZES_DlA]-()-[:UPREGULATES_AuG]-(n2))
RETURN path
结果如图 4.11 所示。
练习
你可以通过修改这些查询,把同样的分析应用到不同疾病上。试着运行一些案例,并通过检索来评估这个 KG 实际捕捉了多少知识。Thinklab 还提供了许多其他值得探索的有趣查询。
正如我们所看到的,KG 能够承载易于导航和使用的知识,而我们的分析则对其中存储的信息给出了定量评估。
图 4.11 清单 4.19 查询结果:展示了乳糜泻(CD)与 “positive regulation of glycoprotein biosynthetic process” 之间的路径。
4.3.2 使用 LLM 辅助解释通路分析结果
虽然基于 DWPC 的查询能够给出生物过程的定量排序结果,但要把这些结果真正转化为临床可执行的洞察,还需要领域知识与上下文理解。LLM 可以作为一种智能解释器,帮助把复杂的通路分析结果综合成连贯的生物学叙事和临床建议。
下面我们就用 CD 分析中的 GO 过程富集结果来演示这一点。查询返回了诸如 “T cell costimulation”、“tolerance induction” 以及 “positive regulation of glycoprotein biosynthetic process” 等过程,并给出了它们对应的 DWPC 分数。LLM 可以帮助我们把这些发现放到更广泛的生物学背景中去解释。
清单 4.20 一个 LLM 分析提示词示例
You are a biomedical research assistant analyzing gene ontology pathway
enrichment results for celiac disease. Please interpret the following
results from a knowledge graph analysis and provide insights for clinical
researchers:
QUERY RESULTS:
- T cell costimulation (DWPC: 0.03347, PC: 10, Genes: 75)
- lymphocyte costimulation (DWPC: 0.03329, PC: 10, Genes: 76)
- tolerance induction (DWPC: 0.03276, PC: 3, Genes: 12)
- positive regulation of T cell activation (DWPC: 0.02925, PC: 14, Genes: 201)
- positive regulation of glycoprotein biosynthetic process
↪(DWPC: 0.00342, PC: 6, Genes: 17)
CONTEXT: These pathways were identified through DWPC analysis of celiac
disease-associated genes in a protein-protein interaction network. DWPC
scores indicate pathway relevance while accounting for node degree bias.
ANALYSIS REQUEST:
1. Interpret the biological significance of these top-ranked pathways in celiac disease
2. Explain the relationship between these processes and celiac disease pathogenesis
3. Identify potential therapeutic implications
4. Highlight any unexpected findings that warrant further investigation
5. Suggest follow-up research questions based on these results
LLM 会把原始分析结果转化为一份完整解释:说明 T 细胞共刺激为何与 CD 的自身免疫特征相关,为什么耐受诱导似乎出现了失调,以及糖蛋白调控为何会与麸质不耐受机制相关。这样的解释,把原本定量的结果转变成了可执行的生物学洞察。下面的侧栏展示了使用 Claude.ai Sonnet 4.0(claude.ai/new)得到的部分结果。
Claude.ai 对“生物学意义”的部分输出结果
T Cell 和 Lymphocyte Costimulation 通路(DWPC:0.03347 和 0.03329)
这些通路代表了乳糜泻中核心的免疫学功能失调。它们较高的 DWPC 分数以及可观的基因数(75–76 个基因),说明失调的共刺激信号是疾病发病机制的中心。在乳糜泻中,抗原呈递细胞通过 HLA-DQ2/DQ8 分子向 T 细胞呈递 gliadin 肽,而异常的共刺激会导致 T 细胞被不恰当地激活,而不是形成耐受。
Tolerance Induction(DWPC:0.03276)
尽管只涉及较少基因(12 个),但这个过程却呈现出极高的 DWPC 分数,这说明它在乳糜泻网络中具有高度互联性。这很可能反映了对膳食抗原口服耐受的根本性失效——而这正是乳糜泻发病机制的一个标志。
Positive Regulation of T Cell Activation(DWPC:0.02925)
涉及 201 个基因,代表了最广泛的免疫调控失衡。持续性的 T 细胞激活驱动了乳糜泻的慢性炎症反应,最终导致绒毛萎缩以及相应的临床症状。
这个例子展示了:LLM 如何通过上下文解释来补充 KG 分析,把定量结果转化为定性理解,从而弥合计算分析与实际应用之间的鸿沟。
4.4 KG 在临床领域的应用
临床领域对 KG 的使用仍处于早期阶段。在这一场景下,长期目标是利用和分析 KG 来支持患者照护,尤其是通过精准医学(precision medicine) 。精准医学计划是一项长期研究工作,其目标是理解一个人的遗传背景、环境与生活方式,如何帮助我们决定最合适的疾病预防或治疗方式。要真正落地精准医学,就需要把蛋白质组学、基因组学、转录组学等 “omics” 数据整合进临床决策过程中,而这个过程又涉及患者数据,如电子健康档案(EHR)。海量且多样的生物医学数据、分散在多个数据库和文献中的临床相关知识,以及隐私问题,都给数据整合带来了挑战 [31]。
EHR 的设计目标,是容纳所有参与患者照护的临床医生所产生的信息。它往往难以解释,也存在相当程度的主观性;某些医生认为“不重要”的信息,可能会被省略或未被继续追踪,从而导致信息缺失 [32]。因此,用于临床场景的 KG,通常会把 EHR 与多组学数据集、多个本体以及其他数据源融合起来。其关键元素包括表示患者、药物和疾病的节点;而边则编码诸如“患者正在接受某种药物治疗”或“患者已被诊断为某种疾病”之类的关系。
另一个使用 EHR 与图技术的例子,是患者旅程映射(patient journey mapping) ,也叫 patient experience mapping [33]。这是一种正在快速发展的方法,旨在更好地理解人们如何进入、经历并离开医疗服务体系。它常常与临床路径(clinical pathways) [34] 相比较:后者定义了对于某类疾病表现的患者,标准照护应如何展开,并且通常会配套一个患者旅程图。图 4.12 展示了一个像癌症这类复杂疾病对应的单个患者旅程范围。
图 4.12 单个患者的肿瘤学临床旅程(图片由 David Hughes 提供;www.graphable.ai/blog/patien…)
研究界正在努力寻找解决方案,以应对在使用 EHR 时涉及的隐私与安全问题。一些方法会利用大量患者数据,提取出关于疾病、症状或治疗结果的统计信息 [32]。这些统计关系以及其权重,会被存入 KG,而真实的患者数据本身则不会直接写入图中。这样做可以显著提升隐私保障 [35]。
另一种方法,是构建一个去标识化、通用化的临床 KG,它基于非敏感数据、匿名化数据、实验结果以及从真实数据中提炼出的统计信息。患者的 EHR 数据只会在绝对必要且获得患者同意时使用。
Albertos Santos 等人 [31] 提出的 Clinical Knowledge Graph(CKG) ,就是一个以 KG 为核心的平台。CKG 通过连接 33 种节点标签和 51 种关系类型来实现数据协调与整合(见图 4.13)。它支持的查询能够帮助发现被改变的功能、为受调控蛋白提出候选药物,并揭示潜在的混杂因素。
图 4.13 Clinical Knowledge Graph 的模式(www.nature.com/articles/s4…)
CKG 以 Neo4j 格式公开提供,地址是 github.com/MannLabs/CK…。我们已经将其升级到撰写本书时可用的最新版本,你可以使用下面的代码,把我们提供的 dump(mng.bz/oZQZ)导入到你的本地环境中。
清单 4.21 导入 CKG 数据库
# Add the following line to the neo4j.conf file
# dbms.databases.seed_from_uri_providers=URLConnectionSeedProvider
# then run the following
CREATE DATABASE ckg OPTIONS { existingData: "use",
↪seedUri: "https://mng.bz/oZQZ"}
现在我们通过一个查询来展示:从像 CKG 这样的 KG 中提取有价值洞察是多么直接。假设你当前的临床研究关注一组蛋白质,并计划开展一项临床试验。其中一部分符合入组条件的患者患有与心肌病(cardiomyopathy) 相关的疾病。你希望检查:在你关注的这些蛋白与各类心肌病相关疾病之间,是否已经存在已知关联。
清单 4.22 查找已知的蛋白质–疾病关联
WITH
['A1BG~P04217','A2M~P01023','ACACB~O00763',
'ACTC1~P68032','ADIPOQ~Q15848','AGT~P01019',
'AIFM2~Q9BRQ8','APOA2~V9GYM3'] as proteins, #1
3 as minScore, #2
"DOID:0050700" as parentDisease #3
MATCH (protein:Protein)-[r]-(disease:Disease) #4
WHERE (
(protein.name+"~"+protein.id) IN proteins) AND
toFloat(r.score)> minScore AND
((disease)-[:HAS_PARENT*0..]->(:Disease {id: parentDisease})) #5
RETURN
(protein.name+"~"+protein.id) AS node1,
disease.name+" <"+disease.id+">" AS node2,
r.score AS weight, type(r) AS type,
r.source AS source
ORDER BY weight DESC
- #1 定义我们感兴趣的蛋白质列表
- #2 定义最小关联强度阈值
- #3 定义目标疾病的 DOID
- #4 匹配任意类型的蛋白质–疾病关联
- #5 匹配所有与心肌病相关的疾病
表 4.5 中的结果显示:某个特定蛋白与多种内源性心肌病之间存在强关联。这个发现为后续可能的深入研究提供了一个具体起点。
注意
DOID 指的是 Disease Ontology Identifier,即疾病本体标识符,定义见 <www.disease-ontology.org>。
表 4.5 清单 4.22 查询结果中的蛋白质–疾病关联
| node1 | node2 | weight | type | source |
|---|---|---|---|---|
| ACTC1~P68032 | intrinsic cardiomyopathy DOID:0060036 | 5 | ASSOCIATED_WITH | DISEASES |
| ACTC1~P68032 | left ventricular noncompaction DOID:0060480 | 5 | ASSOCIATED_WITH | DISEASES |
| ACTC1~P68032 | familial hypertrophic cardiomyopathy DOID:0080326 | 5 | ASSOCIATED_WITH | DISEASES |
| ACTC1~P68032 | hypertrophic cardiomyopathy DOID:11984 | 5 | ASSOCIATED_WITH | DISEASES |
| ACTC1~P68032 | dilated cardiomyopathy DOID:12930 | 5 | ASSOCIATED_WITH | DISEASES |
| ACTC1~P68032 | restrictive cardiomyopathy DOID:397 | 5 | ASSOCIATED_WITH | DISEASES |
4.4.1 LLM 引导下的临床决策支持分析
临床 KG 中包含患者、治疗与结局之间复杂的关系,这些关系需要谨慎解释。LLM 可以帮助临床医生和研究人员把多维临床数据综合成连贯的治疗建议与研究方向。沿用我们的 CKG 分析结果——即发现 ACTC1 蛋白与多种心肌病之间存在强关联——LLM 可以进一步提供临床语境与决策支持。
清单 4.23 一个临床分析用的 LLM 提示词示例
You are a clinical informatics specialist analyzing protein-disease
associations from electronic health records integrated with biomedical
knowledge graphs. Provide clinical decision support based on these
findings:
CLINICAL SCENARIO: Research study targeting proteins in patients with cardiomyopathy-related diseases
KNOWLEDGE GRAPH FINDINGS:
- ACTC1~P68032 shows strong associations (score: 5.0) with:
* Intrinsic cardiomyopathy (DOID:0060036)
* Left ventricular noncompaction (DOID:0060480)
* Familial hypertrophic cardiomyopathy (DOID:0080326)
* Hypertrophic cardiomyopathy (DOID:11984)
* Dilated cardiomyopathy (DOID:12930)
* Restrictive cardiomyopathy (DOID:397)
TARGET PROTEIN LIST: ↪['A1BG~P04217','A2M~P01023','ACACB~O00763','ACTC1~P68032','ADIPOQ~Q15848',↪'AGT~P01019','AIFM2~Q9BRQ8','APOA2~V9GYM3']
CLINICAL REQUEST:
1. Interpret the clinical significance of ACTC1's broad cardiomyopathy associations
2. What does this suggest about patient stratification for clinical trials?
3. Identify potential safety considerations for the research study
4. Recommend additional screening or monitoring protocols
5. Suggest companion biomarkers or genetic testing approaches
6. Propose modifications to inclusion/exclusion criteria based on these findings
这种由 LLM 辅助的分析,有助于把 KG 中的计算发现转化为现实中的临床决策支持,从而为患者照护与研究方案设计提供帮助。由于结果篇幅过长,这里不完整展示;你可以把这个提示词当作练习,拿去你常用的任一 LLM 工具中试试看。
注意
我们并不建议在没有医生和研究人员适当解读的前提下,直接使用 LLM 输出结果。我们的目的,是展示 LLM 如何把从大型 KG 中抽取的复杂数据转化为可解释的洞察。请记住,我们的目标是通过 IAS 赋能人类,而不是替代人类!
小结
- 从结构化数据源构建知识图谱,需要对异构数据集进行系统化整合。这个过程包括实体解析、模式对齐以及数据质量验证,以形成一致且可查询的知识表示。
- 像弱连通分量(WCC)和 Louvain 这样的聚类算法,可以帮助我们理解任意多源 KG 的整体结构与社区组织方式。
- 针对子图的分析指标,如密度、电导率,以及最大连通分量相对大小,为评估 KG 在不同领域中的质量与完整性提供了量化方法。
- 更高级的基于路径的指标,例如度加权路径计数(DWPC),能够比简单路径计数更精细地分析关系模式与实体相关性。
- 像 Hetionet、PPI 网络和 CKG 这样的综合性 KG,是展示整合技术与分析方法的理想实验平台。
- 借助 LLM 对 KG 分析结果进行辅助解释,可以把定量指标转化为可执行的领域洞察与研究假设。
[1] 本书作者之一 Alessandro 的女儿正患有这种疾病。因此,我们可以很方便地验证结果,而无需成为该领域专家。
如果你愿意,我下一步可以继续把这章中的 生物医学术语、图分析术语、Cypher 查询说明 再统一润色成更像正式出版物的中文版本。