跳转至

53. 知识图谱入门与构建

一句话说明:知识图谱是"用实体-关系-实体的网络结构来存储和推理知识"的技术——把散落在各处的知识点串成一张大网,让计算机不仅能存数据,还能像人一样"联想"和"推理"。


目录

  1. 什么是知识图谱
  2. 核心概念详解
  3. 知识图谱 vs 关系数据库 vs 向量数据库
  4. 知识图谱构建流程
  5. 常用工具
  6. LLM + 知识图谱(GraphRAG)
  7. 生信中的知识图谱
  8. Python 实操:用 NetworkX 构建基因互作网络
  9. 常见报错与解决方案
  10. 面试怎么答
  11. 速查表
  12. 延伸资源

1. 什么是知识图谱

1.1 白话解释

知识图谱(Knowledge Graph, KG) 就是一张"知识地图"。

想象你在画一张思维导图:中间写"2型糖尿病",拉一条线到"胰岛素抵抗"写上"病因",再拉一条线到"二甲双胍"写上"治疗药物",再拉一条线到"Akkermansia muciniphila"写上"相关菌群"。这张思维导图里的每个圆圈是"实体"(entity)每条连线是"关系"(relation)。把这种结构规模化,存到计算机里,就是知识图谱。

正式定义:知识图谱是一种用图结构(节点+边)来表示和存储知识的知识库。节点代表实体(如基因、疾病、药物),边代表实体之间的关系(如"抑制""表达""治疗")。根据 Wikipedia,知识图谱使用图结构的数据模型来表示和操作数据,存储实体的互连描述,同时编码这些实体底层的语义关系。

1.2 知识图谱的"前世今生"

时期事件意义
2001 年Tim Berners-Lee 提出语义网(Semantic Web)奠定了用结构化方式组织互联网知识的理念
2012 年Google 推出 Knowledge Graph"知识图谱"概念正式火起来,搜索不再只是匹配关键词
2015-2020 年各大公司构建行业知识图谱金融风控、医疗诊断、推荐系统广泛应用
2023-2026 年LLM + KG(GraphRAG)兴起大模型 + 知识图谱结合,解决幻觉问题

1.3 知识图谱能干什么

  • 智能搜索:搜"糖尿病的治疗药物有哪些副作用",通过关系链自动推理
  • 推荐系统:京东、淘宝用商品知识图谱做"猜你喜欢"
  • 医学诊断辅助:症状→疾病→药物→禁忌的关系推理
  • 生信研究:基因-疾病关联发现、药物靶点预测、蛋白质互作分析

2. 核心概念详解

2.1 三元组(Triple)

知识图谱最基本的单位,格式:(主语, 谓语, 宾语),也叫 (头实体, 关系, 尾实体)

白话:就是一句最简单的"谁-怎么样-谁"。

例子:
  (TP53, 抑制, 细胞增殖)        → 基因TP53抑制细胞增殖
  (二甲双胍, 治疗, 2型糖尿病)   → 二甲双胍治疗2型糖尿病
  (BRCA1, 关联, 乳腺癌)         → BRCA1基因和乳腺癌有关联

白话比方:三元组就像一句主谓宾的句子。"小明(主)-喜欢(谓)-篮球(宾)"就是一个三元组。整个知识图谱就是由无数这样的简单句子组成的。

2.2 本体(Ontology)

白话解释:本体是"知识图谱的词典+语法规则"。它定义了: - 有哪些类别(class):比如"基因""疾病""药物""菌种" - 有哪些关系类型:比如"治疗""抑制""编码""互作" - 层级关系:比如"乳腺癌"是"癌症"的子类,"癌症"是"疾病"的子类

白话比方:
  本体 = 字典 + 语法书
  - 字典告诉你有哪些"词"可以用(实体类别和关系类别)
  - 语法书告诉你"词"之间怎么组合才合法

  比如:你不能写"TP53 治疗 大肠杆菌"(基因不能"治疗"菌),
  因为本体规定"治疗"关系只能是"药物→疾病"。

生信中常见的本体:Gene Ontology(GO)Disease Ontology(DO)Human Phenotype Ontology(HPO)

2.3 RDF(资源描述框架)

白话解释:RDF(Resource Description Framework)是 W3C 制定的一种数据格式标准,专门用来描述三元组。

根据 W3C 定义,RDF 是一种描述和交换图数据的方法,最初由万维网联盟(W3C)设计为元数据的数据模型。它用有向图的三元组语句表示:(1) 主语节点,(2) 从主语到宾语的弧(表示谓语),(3) 宾语节点。

白话比方:
  三元组是"知识的内容",RDF 是"把知识写下来的格式"。
  就像"你好"是内容,JSON/XML/CSV 是把它存下来的格式。

RDF 三元组示例(Turtle 格式):
  <http://example.org/TP53>  <http://example.org/inhibits>  <http://example.org/CellProliferation> .

  翻译:TP53 抑制 细胞增殖

2.4 SPARQL

白话解释:SPARQL(读作"sparkle")是专门查询 RDF 知识图谱的语言,地位相当于关系数据库的 SQL。

SPARQL 是一种 RDF 查询语言,即用于数据库的语义查询语言,能够检索和操作以 RDF 格式存储的数据。它由 W3C 标准化,SPARQL 1.0 于 2008 年成为官方推荐标准,SPARQL 1.1 于 2013 年发布。

# 查询所有和2型糖尿病相关的基因
SELECT ?gene ?relation
WHERE {
  ?gene ?relation <http://example.org/T2D> .  # 找所有和T2D有关系的基因
  ?gene a <http://example.org/Gene> .          # 限定类型是基因
}
白话比方:
  SQL 是问关系数据库的话(SELECT * FROM 表 WHERE ...)
  SPARQL 是问知识图谱的话(找出所有和XX有关系的实体)

2.5 属性图(Property Graph)

白话解释:属性图是另一种存储知识图谱的模型,比 RDF 更灵活、更直观。

特性RDF 图属性图
节点用 URI 标识可以有任意属性(键值对)
只有类型可以有类型 + 属性(如权重、置信度)
查询语言SPARQLCypher(Neo4j)/ Gremlin
适合场景语义网、开放数据集互联企业应用、社交网络、生信网络
白话区别更学术、标准化更工程化、灵活好用
属性图示例(Cypher 语法):
  (:Gene {name:"TP53", chromosome:"17"})    ← 节点有属性
  -[:INHIBITS {confidence:0.95}]->           ← 边也有属性
  (:BiologicalProcess {name:"CellProliferation"})

3. 知识图谱 vs 关系数据库 vs 向量数据库

这三种是完全不同的数据存储思路,别搞混:

对比项关系数据库(MySQL)向量数据库(ChromaDB)知识图谱(Neo4j)
数据模型表格(行+列)高维向量图(节点+边)
存什么结构化数据文本/图片的数字表示实体之间的关系
查询方式SQL 精确匹配相似度搜索(最近邻)图遍历/路径查询
擅长回答"TP53 在哪个染色体上?""哪些基因和 TP53 描述最像?""TP53 通过哪些路径影响糖尿病?"
推理能力无(只能查存进去的数据)无(只能找相似的)有(能沿关系链推理新知识)
索引类型B-Tree / HashHNSW / IVF图索引(邻接表)
典型产品MySQL / PostgreSQLFAISS / Milvus / ChromaDBNeo4j / JanusGraph / Amazon Neptune

白话总结: - 关系数据库像 Excel 表格——查"某一行某一列"的精确数据 - 向量数据库像"以图搜图"——找最相似的内容 - 知识图谱像思维导图——沿着关系链条做推理和联想

三者可以互补:很多系统同时使用。比如 GraphRAG 就是"向量数据库做初步检索 + 知识图谱做关系推理 + LLM 生成回答"。


4. 知识图谱构建流程

构建知识图谱就像从一堆论文里手动画思维导图,但用程序自动化:

原始数据 → 知识抽取 → 实体识别 → 关系抽取 → 知识融合 → 存储 → 推理/应用
   ↓          ↓          ↓          ↓          ↓        ↓       ↓
 论文/数据库  NLP处理   找出实体   找出关系    去重合并  Neo4j  发现新知识

4.1 知识抽取(Knowledge Extraction)

白话:从非结构化文本(论文、报告)或半结构化数据(HTML、表格)中,把有用的知识"挖"出来。

输入:"TP53基因的突变与多种癌症类型密切相关,包括乳腺癌和肺癌。"
输出:
  实体:[TP53, 乳腺癌, 肺癌]
  关系:[(TP53, 关联, 乳腺癌), (TP53, 关联, 肺癌)]

4.2 实体识别(Named Entity Recognition, NER)

白话:从文本中找出"哪些词是基因名、哪些是疾病名、哪些是药物名"。

常用工具: - 通用 NER:spaCy、NLTK、HuggingFace NER 模型 - 生信 NER:PubTator(NCBI 的生物医学文本挖掘工具)、BioBERT、SciSpacy

4.3 关系抽取(Relation Extraction)

白话:识别出实体后,判断它们之间是什么关系。"TP53 抑制 细胞增殖"中,"抑制"就是关系。

方法: - 规则匹配:用正则或依存句法树提取 - 监督学习:训练分类模型判断两个实体间的关系类型 - LLM 抽取:直接让 GPT/Claude 从文本中提取三元组(2024-2026 年主流方式)

4.4 知识融合(Knowledge Fusion)

白话:不同数据源对同一个东西可能叫不同名字。比如"大肠杆菌"="E. coli"="Escherichia coli",需要合并成一个实体。

关键任务: - 实体对齐:把指代同一事物的不同名称统一(Entity Alignment) - 实体消歧:区分同名不同义(如 "JAK" 可能是基因名也可能是人名) - 冲突解决:不同来源说的不一样时,按可信度排序

4.5 知识存储

把处理好的三元组存入图数据库:

存储方案适合场景查询语言
Neo4j企业级图数据库,功能强大Cypher
RDF 三元组存储(Virtuoso、GraphDB)语义网、开放数据集SPARQL
NetworkX(内存图)小规模分析、原型验证Python API
Amazon Neptune云上大规模图Cypher / SPARQL

4.6 知识推理(Knowledge Reasoning)

白话:根据已有的关系,推断出新的关系。

已知:
  (药物A, 靶向, 蛋白质B)
  (蛋白质B, 参与, 通路C)
  (通路C, 关联, 疾病D)

推理:
  → 药物A 可能对 疾病D 有治疗作用(药物重定位/Drug Repurposing)

推理方法: - 基于规则:手写推理规则(如 TransE、RotatE 等嵌入模型) - 知识图谱嵌入:把实体和关系映射到向量空间,用向量运算做推理 - 图神经网络(GNN):用深度学习在图上做预测(链接预测、节点分类)


5. 常用工具

5.1 Neo4j(图数据库)

Neo4j 是一个图数据库管理系统,由 Neo4j Inc. 开发。它用 Java 实现,通过 Cypher 查询语言访问,支持 ACID 事务,是目前最流行的图数据库。

// 创建基因节点
CREATE (:Gene {name: 'TP53', chromosome: '17p13.1'})

// 创建疾病节点
CREATE (:Disease {name: 'Breast Cancer', icd10: 'C50'})

// 创建关系
MATCH (g:Gene {name: 'TP53'}), (d:Disease {name: 'Breast Cancer'})
CREATE (g)-[:ASSOCIATED_WITH {evidence: 'GWAS', pvalue: 1e-8}]->(d)

// 查询:找出和乳腺癌相关的所有基因
MATCH (g:Gene)-[:ASSOCIATED_WITH]->(d:Disease {name: 'Breast Cancer'})
RETURN g.name, g.chromosome

安装:Docker 一键启动(推荐)

docker pull neo4j:5-community    # 拉取社区版镜像
docker run -d \
  --name neo4j \
  -p 7474:7474 -p 7687:7687 \   # 7474=Web界面, 7687=Bolt协议
  -e NEO4J_AUTH=neo4j/password \ # 设置用户名密码
  neo4j:5-community
# 浏览器访问 http://localhost:7474 即可看到可视化界面

5.2 NetworkX(Python 图分析库)

NetworkX 是 Python 的图/网络分析库(当前版本 3.6.1),适合中小规模图的分析和可视化。不需要安装数据库,纯 Python 内存操作。

适合场景:学术研究、原型验证、几万节点以内的图分析

5.3 py2neo(Python 操作 Neo4j)

py2neo 是从 Python 连接和操作 Neo4j 的客户端库和工具包,提供了面向对象的 API,比直接写 Cypher 更 Pythonic。

from py2neo import Graph, Node, Relationship  # 导入核心类

graph = Graph("bolt://localhost:7687", auth=("neo4j", "password"))  # 连接数据库

# 创建节点
gene = Node("Gene", name="TP53", chromosome="17")     # 创建基因节点
disease = Node("Disease", name="Breast Cancer")        # 创建疾病节点

# 创建关系并提交
rel = Relationship(gene, "ASSOCIATED_WITH", disease)   # 创建关系
graph.create(rel)                                       # 写入数据库

注意:py2neo 已不再积极维护(最后更新 2023 年)。Neo4j 官方推荐使用 neo4j Python driver:pip install neo4j

5.4 工具选型指南

场景推荐工具理由
快速原型/学术研究NetworkX零依赖,纯 Python,适合几千到几万节点
生产级图存储Neo4jACID 事务,可视化界面,Cypher 强大
语义网/开放数据GraphDB / Virtuoso原生支持 RDF + SPARQL
大规模分布式图Amazon Neptune / TigerGraph云原生,水平扩展
LLM + 知识图谱Microsoft GraphRAG + Neo4j最成熟的 GraphRAG 方案

6. LLM + 知识图谱(GraphRAG)

6.1 为什么需要 GraphRAG

普通 RAG(检索增强生成)的问题: - 只能做局部检索——找到和问题最相似的几个文档片段 - 无法回答全局性问题——"整个数据集里最重要的主题是什么?" - 缺乏多跳推理——"A 和 D 之间通过 B、C 有什么关联?"

GraphRAG 的解决方案:先把文档构建成知识图谱,再在图上做推理+检索,最后交给 LLM 生成回答。

6.2 微软 GraphRAG

微软于 2024 年开源的 GraphRAG 项目是目前最成熟的方案。根据其官方描述,GraphRAG 是一个数据管道和转换套件,旨在使用 LLM 的能力从非结构化文本中提取有意义的结构化数据。它使用知识图谱记忆结构来增强 LLM 输出。

核心流程

文档 → LLM 抽取实体和关系 → 构建知识图谱 → 社区检测(Leiden算法)
                              查询 ← 社区摘要 ← 层次化摘要生成

两种查询模式: - Local Search(局部搜索):适合"TP53 有什么功能?"这类具体问题 - Global Search(全局搜索):适合"这批数据的主要发现是什么?"这类综合问题

6.3 GraphRAG 快速体验

# 安装(需要 Python 3.10+)
pip install graphrag                     # 安装 GraphRAG

# 初始化项目
graphrag init --root ./my_project        # 创建配置文件

# 配置 settings.yaml,填入 LLM API key

# 建立索引(将文档转化为知识图谱)
graphrag index --root ./my_project       # 开始构建图谱

# 查询
graphrag query --root ./my_project \
  --method local \                       # 局部搜索模式
  --query "TP53基因有哪些功能?"          # 你的问题

注意:GraphRAG 索引过程会大量调用 LLM API,成本较高。建议先用小数据集测试。

6.4 GraphRAG vs 普通 RAG

对比项普通 RAGGraphRAG
检索方式向量相似度图遍历 + 向量相似度
推理能力单跳(找最相似的片段)多跳(沿关系链推理)
全局问题表现差通过社区摘要回答全局问题
构建成本低(只需 Embedding)高(需要 LLM 抽取实体关系)
适合场景简单问答复杂分析、报告生成、全局总结

7. 生信中的知识图谱

知识图谱在生物信息学中有重要应用。根据近年文献,知识图谱越来越多地用于科学研究,特别是在基因组学、蛋白质组学和系统生物学领域。

7.1 基因-疾病关系图

典型数据库: - DisGeNET:收录了基因/变异与疾病的关联,包含 >1.1M 基因-疾病关联 - OMIM:人类孟德尔遗传在线数据库 - ClinVar:变异-疾病关联数据库

应用示例:
  查询"2型糖尿病相关的所有基因"
  → DisGeNET 返回 TCF7L2、PPARG、KCNJ11、SLC30A8 等数百个基因
  → 按证据等级(GDA score)排序
  → 结合通路分析,发现主要涉及胰岛素信号通路、糖代谢通路

7.2 蛋白质互作网络(PPI Network)

典型数据库: - STRING:蛋白质互作数据库(>67M 蛋白质,>20B 互作对) - BioGRID:基因和蛋白质互作数据库 - IntAct:分子互作数据库

白话:蛋白质互作网络就是"哪些蛋白质会互相结合/影响"的关系图。
在这个图里:
  - 节点 = 蛋白质
  - 边 = 两个蛋白质之间有物理结合或功能关联
  - 边的权重 = 互作的置信度分数

7.3 药物-靶点知识图谱

典型数据库: - DrugBank:药物信息 + 靶点数据库 - ChEMBL:生物活性化合物数据库 - TTD(Therapeutic Target Database):治疗靶点数据库

应用场景 — 药物重定位(Drug Repurposing):
  已知:药物A → 靶向蛋白质B → 蛋白质B参与通路C → 通路C关联疾病D
  推断:药物A 可能治疗 疾病D

  真实案例:通过知识图谱推理,发现已有药物对 COVID-19 可能有效

7.4 示例项目可以怎么用

结合该 T2D 肠道菌群项目:

构建一个小型知识图谱:
  菌种(如 Akkermansia)→ 产生 → 代谢物(如短链脂肪酸)
  代谢物 → 影响 → 宿主通路(如胰岛素信号通路)
  宿主通路 → 关联 → 疾病(2型糖尿病)
  菌种 → 差异丰度 → 疾病组/健康组

用 NetworkX 或 Neo4j 存储和可视化,面试时展示"我不仅做了统计分析,
还构建了菌群-代谢-疾病的知识图谱来理解机制"。

8. Python 实操:用 NetworkX 构建基因互作网络

8.1 完整代码(带详细中文注释)

"""
实操:用 NetworkX 构建一个简单的基因-疾病-药物知识图谱
场景:模拟 2 型糖尿病相关的基因、通路、药物关系网络
"""

import networkx as nx                  # 导入 NetworkX 图分析库
import matplotlib.pyplot as plt        # 导入绑图库
import matplotlib                      # 导入 matplotlib 用于设置中文字体

# ============================================================
# 第一步:创建有向图(关系有方向,如"基因A → 抑制 → 通路B")
# ============================================================
G = nx.DiGraph()                       # DiGraph = Directed Graph,有向图

# ============================================================
# 第二步:添加节点(实体),每个节点带有属性
# ============================================================
# 基因节点
G.add_node("TCF7L2", type="gene", description="转录因子,T2D最强风险基因")   # 添加基因节点
G.add_node("PPARG", type="gene", description="过氧化物酶体增殖活化受体γ")    # 另一个T2D相关基因
G.add_node("INS", type="gene", description="胰岛素基因")                     # 胰岛素基因
G.add_node("SLC30A8", type="gene", description="锌转运蛋白,影响胰岛素分泌") # 锌转运体基因
G.add_node("KCNJ11", type="gene", description="钾通道基因,调控胰岛素释放") # 钾通道基因

# 疾病节点
G.add_node("T2D", type="disease", description="2型糖尿病")                   # 疾病节点
G.add_node("Obesity", type="disease", description="肥胖症")                  # 肥胖症

# 药物节点
G.add_node("Metformin", type="drug", description="二甲双胍,一线降糖药")     # 二甲双胍
G.add_node("Pioglitazone", type="drug", description="吡格列酮,PPARγ激动剂") # 吡格列酮

# 通路节点
G.add_node("InsulinPathway", type="pathway", description="胰岛素信号通路")   # 胰岛素通路
G.add_node("WntPathway", type="pathway", description="Wnt信号通路")          # Wnt通路

# 菌群节点(结合你的研究方向)
G.add_node("Akkermansia", type="microbe", description="嗜黏蛋白阿克曼菌")   # 有益菌
G.add_node("SCFA", type="metabolite", description="短链脂肪酸")              # 代谢物

# ============================================================
# 第三步:添加边(关系),每条边带有关系类型和权重
# ============================================================
# 基因-疾病关联
G.add_edge("TCF7L2", "T2D", relation="risk_gene_for", weight=0.95)     # TCF7L2是T2D风险基因
G.add_edge("PPARG", "T2D", relation="risk_gene_for", weight=0.88)      # PPARG也是T2D风险基因
G.add_edge("INS", "T2D", relation="risk_gene_for", weight=0.85)        # 胰岛素基因关联T2D
G.add_edge("SLC30A8", "T2D", relation="risk_gene_for", weight=0.80)    # SLC30A8关联T2D
G.add_edge("KCNJ11", "T2D", relation="risk_gene_for", weight=0.82)    # KCNJ11关联T2D
G.add_edge("PPARG", "Obesity", relation="risk_gene_for", weight=0.75)  # PPARG也关联肥胖

# 基因-通路关系
G.add_edge("TCF7L2", "WntPathway", relation="participates_in", weight=0.9)     # TCF7L2参与Wnt通路
G.add_edge("PPARG", "InsulinPathway", relation="regulates", weight=0.85)       # PPARG调控胰岛素通路
G.add_edge("INS", "InsulinPathway", relation="participates_in", weight=0.95)   # 胰岛素参与胰岛素通路

# 药物-基因/通路关系
G.add_edge("Pioglitazone", "PPARG", relation="targets", weight=0.92)           # 吡格列酮靶向PPARG
G.add_edge("Metformin", "InsulinPathway", relation="modulates", weight=0.88)   # 二甲双胍调节胰岛素通路

# 药物-疾病关系
G.add_edge("Metformin", "T2D", relation="treats", weight=0.95)         # 二甲双胍治疗T2D
G.add_edge("Pioglitazone", "T2D", relation="treats", weight=0.80)      # 吡格列酮治疗T2D

# 菌群相关关系
G.add_edge("Akkermansia", "SCFA", relation="produces", weight=0.7)     # Akkermansia产生SCFA
G.add_edge("SCFA", "InsulinPathway", relation="activates", weight=0.6) # SCFA激活胰岛素通路
G.add_edge("Metformin", "Akkermansia", relation="enriches", weight=0.65) # 二甲双胍富集Akkermansia

# ============================================================
# 第四步:图分析——计算节点重要性
# ============================================================
# 度中心性:一个节点连了多少边(越多越重要)
degree_cent = nx.degree_centrality(G)  # 计算每个节点的度中心性

# 介数中心性:一个节点在多少最短路径上(越多说明越是"桥梁")
betweenness = nx.betweenness_centrality(G)  # 计算介数中心性

# PageRank:类似Google排名,被重要节点连接的节点更重要
pagerank = nx.pagerank(G, weight='weight')  # 计算PageRank值

# 打印分析结果
print("=" * 60)
print("节点重要性排名(按 PageRank)")
print("=" * 60)
sorted_pr = sorted(pagerank.items(), key=lambda x: x[1], reverse=True)  # 按PageRank降序排列
for node, score in sorted_pr:                       # 遍历排序后的结果
    node_type = G.nodes[node].get('type', '?')      # 获取节点类型
    print(f"  {node:18s} (type={node_type:10s})  PageRank={score:.4f}"  # 格式化输出
          f"  Degree={degree_cent[node]:.3f}"        # 度中心性
          f"  Betweenness={betweenness[node]:.3f}")  # 介数中心性

# ============================================================
# 第五步:路径查询——药物如何通过知识图谱关联到疾病
# ============================================================
print("\n" + "=" * 60)
print("路径分析:Akkermansia 如何与 T2D 关联?")
print("=" * 60)

# 查找所有简单路径(不重复经过同一节点)
for path in nx.all_simple_paths(G, "Akkermansia", "T2D", cutoff=4):  # cutoff=最多经过4步
    relations = []                                   # 存储路径上的关系
    for i in range(len(path) - 1):                   # 遍历路径中相邻节点对
        edge_data = G.edges[path[i], path[i+1]]      # 获取边的属性
        relations.append(edge_data.get('relation', '?'))  # 提取关系名
    path_str = ""                                    # 构建可读的路径字符串
    for i, node in enumerate(path):                  # 遍历路径中的节点
        path_str += node                              # 添加节点名
        if i < len(relations):                        # 如果后面还有关系
            path_str += f" --[{relations[i]}]--> "    # 添加关系箭头
    print(f"  路径: {path_str}")                      # 打印完整路径

# ============================================================
# 第六步:可视化
# ============================================================
plt.figure(figsize=(14, 10))                         # 设置画布大小

# 按节点类型分配颜色
color_map = {                                        # 定义颜色映射
    "gene": "#4ECDC4",       # 青绿色 = 基因
    "disease": "#FF6B6B",    # 红色 = 疾病
    "drug": "#45B7D1",       # 蓝色 = 药物
    "pathway": "#96CEB4",    # 绿色 = 通路
    "microbe": "#FFEAA7",    # 黄色 = 微生物
    "metabolite": "#DDA0DD", # 紫色 = 代谢物
}

node_colors = [color_map.get(G.nodes[n].get('type', ''), '#999')  # 根据类型获取颜色
               for n in G.nodes()]                                  # 对每个节点

# 按 PageRank 调整节点大小
node_sizes = [pagerank[n] * 8000 + 500 for n in G.nodes()]  # PageRank越大节点越大

# 布局算法:spring_layout 模拟弹簧力,让图看起来更美观
pos = nx.spring_layout(G, k=2, seed=42)              # k控制节点间距,seed固定布局

# 画边(带箭头)
nx.draw_networkx_edges(G, pos,                        # 画边
                       edge_color='#888888',           # 灰色边
                       arrows=True,                    # 显示箭头
                       arrowsize=15,                   # 箭头大小
                       width=1.5,                      # 线宽
                       alpha=0.6)                      # 透明度

# 画节点
nx.draw_networkx_nodes(G, pos,                         # 画节点
                       node_color=node_colors,          # 节点颜色
                       node_size=node_sizes,            # 节点大小
                       edgecolors='black',              # 节点边框颜色
                       linewidths=1.5)                  # 边框线宽

# 画节点标签
nx.draw_networkx_labels(G, pos, font_size=9, font_weight='bold')  # 节点名称

# 画边标签(关系名)
edge_labels = {(u, v): d['relation']                   # 提取关系名作为边标签
               for u, v, d in G.edges(data=True)}
nx.draw_networkx_edge_labels(G, pos,                    # 画边上的关系标签
                             edge_labels=edge_labels,
                             font_size=7,
                             font_color='#555555')

plt.title("T2D Gene-Disease-Drug Knowledge Graph", fontsize=16, fontweight='bold')  # 标题
plt.legend(handles=[                                    # 添加图例
    plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=c, markersize=12, label=t)
    for t, c in color_map.items()
], loc='upper left', fontsize=10)
plt.axis('off')                                         # 隐藏坐标轴
plt.tight_layout()                                      # 自动调整布局
plt.savefig("t2d_knowledge_graph.png", dpi=150, bbox_inches='tight')  # 保存图片
plt.show()                                              # 显示图形
print("\n图谱已保存为 t2d_knowledge_graph.png")

# ============================================================
# 第七步:导出为 GraphML 格式(可导入 Neo4j / Cytoscape)
# ============================================================
nx.write_graphml(G, "t2d_knowledge_graph.graphml")      # 导出为标准 GraphML 格式
print("图谱数据已导出为 t2d_knowledge_graph.graphml")   # 可以用 Cytoscape 打开可视化

8.2 运行方法

# 激活 conda 环境
conda activate bioinfo                 # 使用你的生信环境

# 安装依赖(如果没装的话)
pip install networkx matplotlib        # NetworkX + 绑图

# 运行脚本
python knowledge_graph_demo.py         # 执行

8.3 预期输出

============================================================
节点重要性排名(按 PageRank)
============================================================
  T2D                (type=disease   )  PageRank=0.1842  Degree=0.538  Betweenness=0.103
  InsulinPathway     (type=pathway   )  PageRank=0.1356  Degree=0.385  Betweenness=0.282
  PPARG              (type=gene      )  PageRank=0.0912  Degree=0.308  Betweenness=0.154
  ...

============================================================
路径分析:Akkermansia 如何与 T2D 关联?
============================================================
  路径: Akkermansia --[produces]--> SCFA --[activates]--> InsulinPathway ...

9. 常见报错与解决方案

报错 / 问题原因解决方案
ModuleNotFoundError: No module named 'networkx'没安装 NetworkXpip install networkx
neo4j.exceptions.ServiceUnavailableNeo4j 没启动或端口不对检查 Docker 是否运行:docker ps
py2neo.errors.ConnectionRefused连接被拒绝确认 Neo4j 端口 7687 开放,密码正确
NetworkX 画图中文乱码matplotlib 缺中文字体plt.rcParams['font.sans-serif'] = ['SimHei']
graphrag index 报 API key 错误没配置 LLM API编辑 settings.yaml,填入正确的 API key
知识图谱节点太多画出来是一团乱节点数量超过可视化极限筛选关键节点(如只画 PageRank top 50),或用 Gephi / Cytoscape
Neo4j 内存不足 OutOfMemoryError图太大,默认内存不够修改 neo4j.confdbms.memory.heap.max_size=4G

10. 面试怎么答

Q1:什么是知识图谱?和传统数据库有什么区别?

知识图谱是用图结构(节点+边)来存储知识的数据库。核心单位是三元组:(实体, 关系, 实体)。和传统关系数据库最大的区别是:关系数据库用表格存数据,查询靠 SQL 做精确匹配;知识图谱用图存数据,可以沿着关系链做多跳推理,发现隐含的知识。比如通过"药物→靶点→通路→疾病"这条关系链做药物重定位。

Q2:知识图谱在生信中有哪些应用?

主要有三个方面:第一,基因-疾病关联分析,比如用 DisGeNET 查某个疾病关联的所有风险基因;第二,蛋白质互作网络(PPI),用 STRING 数据库构建互作图,做 Hub 基因筛选和模块分析;第三,药物重定位,通过知识图谱推理已有药物对新疾病的潜在治疗作用。在该 T2D 项目中,也可以构建"菌群-代谢物-宿主通路-疾病"的小型知识图谱来辅助理解机制。

Q3:请解释 RDF 和属性图的区别。

两者都是知识图谱的存储模型。RDF 是 W3C 标准,用 URI 标识每个实体,三元组格式是(主语, 谓语, 宾语),查询用 SPARQL。优点是标准化程度高,适合开放数据集互联。属性图模型中,节点和边都可以带任意属性(键值对),查询用 Cypher(Neo4j),更灵活更工程化。生信研究中,做蛋白质互作网络分析用属性图更方便,因为边上需要存权重、实验方法等属性。

Q4:什么是 GraphRAG?和普通 RAG 有什么区别?

GraphRAG 是微软提出的方法,核心思路是先用 LLM 从文档中抽取实体和关系构建知识图谱,再通过社区检测算法(Leiden)做层次化聚类和摘要。和普通 RAG 的区别:普通 RAG 只能做向量相似度检索,找最相关的文本片段;GraphRAG 能做多跳推理和全局总结,比如"这批数据最重要的发现是什么"这种全局性问题,普通 RAG 答不好,GraphRAG 通过社区摘要可以回答。代价是构建成本更高。

Q5:你如何用 Python 构建一个简单的知识图谱?

用 NetworkX 库。首先用 nx.DiGraph() 创建有向图,然后用 add_node() 添加实体节点,每个节点带类型和描述属性;用 add_edge() 添加关系边,带关系名和权重属性。分析方面,可以计算度中心性找出连接最多的 Hub 节点,计算介数中心性找出关键"桥梁"节点,用 all_simple_paths() 查找两个实体之间的所有路径。如果数据量大,建议用 Neo4j 存储,用 py2neo 或 neo4j Python driver 操作。


11. 速查表

核心概念速查

概念一句话解释类比
知识图谱用"实体-关系-实体"组成的网络存知识超大号思维导图
三元组(头实体, 关系, 尾实体)一句主谓宾的句子
本体定义有哪些类和关系的"规则书"字典 + 语法规则
RDFW3C 标准的图数据格式知识的"存储格式"
SPARQL查询 RDF 图的语言知识图谱的 SQL
属性图节点和边都能带属性的图模型更灵活的 RDF
CypherNeo4j 的查询语言属性图的 SQL

构建流程速查

知识抽取 → 实体识别(NER) → 关系抽取(RE) → 知识融合(对齐+消歧) → 存储(Neo4j) → 推理(GNN/嵌入)

Python NetworkX 常用操作速查

import networkx as nx                         # 导入

G = nx.DiGraph()                              # 创建有向图
G = nx.Graph()                                # 创建无向图

G.add_node("A", type="gene")                  # 添加带属性的节点
G.add_edge("A", "B", relation="inhibits")     # 添加带属性的边

G.nodes()                                     # 所有节点
G.edges(data=True)                            # 所有边(含属性)
G.degree("A")                                 # 节点A的度
G.neighbors("A")                              # 节点A的邻居

nx.degree_centrality(G)                       # 度中心性
nx.betweenness_centrality(G)                  # 介数中心性
nx.pagerank(G)                                # PageRank
nx.shortest_path(G, "A", "B")                 # 最短路径
nx.all_simple_paths(G, "A", "B", cutoff=3)    # 所有简单路径

nx.write_graphml(G, "out.graphml")            # 导出 GraphML
nx.read_graphml("out.graphml")                # 读取 GraphML

Neo4j Cypher 常用操作速查

CREATE (:Gene {name:'TP53'})                                -- 创建节点
MATCH (g:Gene {name:'TP53'}) RETURN g                       -- 查询节点
MATCH (a)-[r]->(b) RETURN a,r,b LIMIT 10                    -- 查看关系
MATCH p=(a)-[*1..3]->(b) RETURN p                           -- 13跳路径查询
MATCH (g:Gene)-[:ASSOCIATED_WITH]->(d:Disease) RETURN g,d   -- 模式匹配

生信知识图谱数据库速查

数据库内容网址
STRING蛋白质互作网络string-db.org
DisGeNET基因-疾病关联disgenet.org
DrugBank药物-靶点数据drugbank.com
Gene Ontology基因功能本体geneontology.org
KEGG代谢通路数据库kegg.jp
Reactome生物通路知识库reactome.org
BioGRID基因/蛋白质互作thebiogrid.org
UniProt蛋白质序列和功能uniprot.org

12. 延伸资源

入门教程

  • NetworkX 官方教程:networkx.org/documentation/stable/tutorial.html(Python 图分析入门,当前版本 3.6.1)
  • Neo4j 官方文档:neo4j.com/docs/(Cypher 查询语言教程)
  • Microsoft GraphRAG:github.com/microsoft/graphrag(LLM + 知识图谱的参考实现)

进阶学习

  • 论文"From Local to Global: A Graph RAG Approach to Query-Focused Summarization"(微软 GraphRAG 原始论文,arXiv:2404.16130)
  • 知识图谱嵌入:TransE、RotatE、CompGCN 等模型的原始论文
  • 图神经网络"A Gentle Introduction to Graph Neural Networks"(Distill.pub)

生信专用资源

  • Hetionet:一个整合了基因、疾病、药物、通路等 11 种实体的异构生物医学知识图谱(github.com/hetio/hetionet)
  • PrimeKG:精准医学知识图谱,整合了 20 个生物医学数据库(Harvard)
  • BioKG:生物医学知识图谱构建框架

与本知识库其他篇目的关系

  • 50 篇(向量数据库):知识图谱做关系推理,向量数据库做相似度搜索,两者互补
  • 02 篇(LangChain + RAG):GraphRAG 是 RAG 的升级版,建议先看 02 篇再看本篇
  • 12 篇(单细胞分析 Scanpy):单细胞分析中的基因调控网络也可以用图来表示
  • 18 篇(多组学整合):多组学整合可以用知识图谱把不同组学层次的数据串联起来