药物重定位研究方法与流程归纳总结
药物重定位,说白了就是给老药找新活。听起来简单,真做起来坑不少。我当年第一次上手重定位项目,天真地以为把几个数据库一合并,跑个网络分析就能出结果。结果呢?数据打架、特征缺失、模型过拟合,折腾了两个月颗粒无收。后来我总结出一套相对稳定的流程,今天分享给你。
整个流程长什么样?
先看整体框架。我个人习惯把重定位拆成五个阶段:数据收集、数据清洗、计算预测、候选筛选、实验验证。每一步都有坑,但走通之后,效率能提升好几个档次。
我的经验:流程图里的五个阶段并不是严格串行。有时候数据清洗完发现特征太少,你得回头补数据。允许循环迭代,别死磕某一步。
第一步:数据收集与整合
重定位的数据,说白了就是两张大表:一张存药物和它的靶点、副作用、适应症;另一张存疾病和它的基因、通路、表型。然后想办法把这两张表连接起来。
常用的公开数据源,我整理了一份清单:
| 数据源 | 内容 | 访问方式 |
|---|---|---|
| DrugBank | 药物-靶点、药物-适应症 | 官网下载 XML/CSV |
| CTD (Comparative Toxicogenomics Database) | 化学物-基因-疾病关联 | REST API / 批量下载 |
| STITCH | 化学物-蛋白质互作 | TSV 文件下载 |
| GEO | 基因表达谱(疾病 vs 正常) | GEOmetadb / Bioconductor |
| LINCS L1000 | 药物扰动后的基因表达变化 | CLUE API / 下载 |
| UniProt | 蛋白质序列、功能、互作 | SPARQL / 批量下载 |
| STRING | 蛋白质-蛋白质互作网络 | API / TSV 导出 |
我曾经栽过一个跟头:从 DrugBank 下载了 XML 版本,结果解析时没注意英文字段里藏了中文注释,导致靶点名称对不上。后来我改用 TSV 版本,并写了个统一归一化的脚本。建议你一开始就统一用 DrugBank ID 或 ChEMBL ID 做主键,省得后面后悔。
第二步:数据预处理与特征工程
数据收集来的原始数据,你想想看,出自不同数据库,命名规范完全不一样。比如“阿司匹林”在 A 库里叫 Aspirin,在 B 库里叫 Acetylsalicylic acid,甚至在 C 库里给出的是 PubChem CID 2244。第一步就是实体对齐。
我常用的对齐工具:
- 基于字典匹配:用 UniChem、PubChem 映射表做交叉查询。
- 文本模糊匹配:对药物名称做 Levenshtein 距离、Jaccard 相似度,阈值设 0.85 以上。
- 人工校验:对齐后抽样 100 条,肉眼过一遍。我吃过亏,自动映射把
Dopamine和Dobutamine当成同一种药,差点闹出笑话。
特征工程这块,我习惯构建三个维度的特征:
- 药物特征:分子指纹(ECFP4、MACCS)、理化性质(LogP、分子量)、副作用标签。
- 疾病特征:差异表达基因集、通路富集得分、表型相似性(基于 HP Ontology)。
- 互作特征:药物靶点与疾病相关基因在蛋白质互作网络中的最短路径、共表达相关性。
写一个简单的 Python 代码片段,用来从 DrugBank 提取药物-靶点关系:
import pandas as pd
import xml.etree.ElementTree as ET
def extract_drug_targets(xml_file):
tree = ET.parse(xml_file)
root = tree.getroot()
records = []
for drug in root.findall('.//drug'):
drug_id = drug.find('drugbank-id').text
targets = drug.findall('.//target')
for target in targets:
target_id = target.find('id').text if target.find('id') is not None else None
records.append((drug_id, target_id))
df = pd.DataFrame(records, columns=['drug_id', 'target_id'])
return df
df = extract_drug_targets('drugbank.xml')
df.to_csv('drug_target_pairs.csv', index=False)
注意:DrugBank XML 文件很大(1.5GB+),解析时别直接一次性加载进内存。建议用迭代式解析 iterparse 或者按分块读取。我当初把内存跑崩了三次才学会这个教训。
第三步:计算预测方法
重定位的计算方法,说白了就是三种套路:相似度匹配、网络传播、机器学习。我各举一个代表性算法:
| 方法类别 | 典型算法 | 适用场景 |
|---|---|---|
| 基于相似度 | 药物-疾病余弦相似度 + 阈值排序 | 有已知适应症数据,特征维度不高 |
| 网络扩散 | Random Walk with Restart (RWR) | 蛋白质互作网络较完整,关系稀疏 |
| 机器学习 | XGBoost / 图神经网络(GNN) | 有足够正负样本,特征工程做得好 |
我个人最推荐 网络扩散 作为基线方法。为什么?因为它不需要大量训练标签,而且能利用网络的全局拓扑结构。我记得有一个项目,用 RWR 在 STRING 网络上跑一轮,Top-50 候选里验证成功率达到了 12%,远高于随机挑选。
RWR 的核心代码示例(Python + NetworkX):
import networkx as nx
import numpy as np
def random_walk_restart(adj_matrix, seed, restart_prob=0.7, max_iter=100):
n = adj_matrix.shape[0]
p = np.zeros(n)
p[seed] = 1.0
# 归一化转移矩阵
M = adj_matrix / adj_matrix.sum(axis=1, keepdims=True)
M = np.nan_to_num(M)
for _ in range(max_iter):
p_new = (1 - restart_prob) * M.T @ p + restart_prob * p_seed
if np.allclose(p, p_new, atol=1e-6):
break
p = p_new
return p
# 假设 G 是 NetworkX 图,seed_node 是疾病相关基因的节点ID
adj = nx.adjacency_matrix(G).todense()
p_seed = np.zeros(adj.shape[0])
p_seed[seed_idx] = 1.0
scores = random_walk_restart(adj, p_seed)
# 对药物节点(非种子)按得分排序
第四步:优先级排序与候选筛选
计算模型通常会输出几百个候选药物。你不可能全拿去实验验证,太贵了。我经常用三层过滤器来筛选:
- 安全性过滤:去掉已知有严重副作用的药。从 SIDER 数据库拉取副作用频率,剔除 hepatotoxicity、cardiotoxicity 高频的药物。
- 可及性过滤:优先选已上市、成本低、专利已过期或即将过期的药物。太新的药反而不适合重定位,数据太少。
- 一致性过滤:看候选药物的已知适应症与目标疾病是否有共享的生物学机制(比如共通路、共靶点)。如果完全不相关,模型可能是在学噪声。
三层过滤之后,Top-10 或 Top-20 基本就是可验证的候选列表了。我建议把候选列表做成一个表格,包含药物名、打分、安全评级、可及性标记、机制一致性说明。这样给 PI 看的时候,人家一眼就能判断。
第五步:实验验证
这一步是重定位真正的“试金石”。计算模型说行不算,体外细胞实验验证了才算。我通常建议做两组实验:
- 体外药效:在疾病相关细胞系中测 EC50 / IC50,和已知标准药对比。
- 安全性快速筛查:测一下对正常细胞的毒性(CC50),算一下选择性指数(SI = CC50 / IC50),SI > 10 才值得推进。
在你做实验之前,记得要先查一下这个药是否已经有人测试过对目标疾病的活性。我有一回白花了两周测一个药,结果发现三个月前刚有论文发表,还是一样的细胞系。真想把那篇论文从脑海里删掉。所以 文献调研要前置,用 PubMed、ClinicalTrials.gov 扫一圈,避免重复造轮子。
核心总结:药物重定位流程没那么神秘,做好数据对齐、选对计算方法、踏实做实验验证。每一步都藏着小坑,但只要按这个框架走,出成果只是时间问题。