拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于知识图谱与推荐系统的药物靶点预测:从数据到AI模型实战

简介本资源是一套面向计算机及相关专业本科生的课程设计与期末大作业实战项目聚焦于生物信息学交叉场景——利用知识图谱与推荐系统协同预测药物-靶点相互作用。项目代码完整、结构清晰涵盖数据预处理如hetionet.py、yamanishi_08.py、知识图谱构建BioKG.py、多种推荐模型实现deepdti.py、kge_rf.py、kge_nfm.py及训练评估全流程配套详细操作指南与环境配置说明Pipfile、requirements.txt、README.md。压缩包共40个文件含9个核心Python脚本、6个.DS_Store占位文件、1个说明文档、1个许可证及若干配置与日志文件整体仅56KB轻量易部署。已有94人学习下载适合具备基础Python与机器学习认知的学生开展项目复现、算法对比或课程报告拓展可直接用于答辩演示、模型调优实践与知识图谱推荐系统融合应用的入门理解。1. 项目缘起当药物研发遇上AI推荐在药物研发这个漫长且昂贵的链条里有一个环节至关重要那就是寻找能与特定疾病靶点通常是蛋白质发生作用的候选药物分子。传统的高通量筛选方法成本动辄数百万美元耗时数月成功率却低得可怜。这感觉就像在茫茫大海里用最原始的渔网去捞一条特定花纹的鱼效率极低。近几年我身边不少做计算化学和生物信息学的朋友开始频繁讨论两个词知识图谱和推荐系统。乍一听这俩一个像是搞“关系网”的一个像是电商平台用的跟药物研发有什么关系但仔细一想逻辑就通了。药物、靶点、疾病、副作用、基因、通路……这些生物医学实体之间存在着海量、复杂、多类型的关系这不正是一个天然的、亟待构建的巨型知识图谱吗而预测一个新药分子是否会和某个靶点结合本质上不就是基于这个“图谱”里已有的“用户”靶点和“商品”药物的交互历史已知的结合关系去给一个“新商品”候选药物做“个性化推荐”吗这个想法让我非常兴奋。于是我决定动手用Python把这一套思路实现出来。目标很明确构建一个轻量级的、可复现的流程整合公开的生物医学数据搭建一个药物-靶点知识图谱然后利用经典的推荐系统算法去预测那些尚未被实验验证的潜在药物-靶点相互作用。这不仅是一个有趣的技术验证项目其产出的预测结果也能为真正的药物发现提供有价值的计算线索和优先级排序。下面我就把这个项目的完整实现思路、代码解析以及实操中会遇到的各种“坑”和技巧毫无保留地分享出来。整个过程涉及数据处理、图谱构建、特征工程、模型训练和评估我会尽量用通俗的语言讲清楚每个步骤背后的“为什么”。2. 核心数据源从哪里获取药物与靶点的“关系网”巧妇难为无米之炊。构建知识图谱和训练推荐模型第一步就是找数据。我们的核心需求是“药物-靶点”的已知相互作用对。这里我强烈推荐一个公开、免费且质量较高的数据库DrugBank。为什么选择DrugBankDrugBank是一个独特的生物信息学和化学信息学资源它详细地结合了药物化学数据和靶点蛋白数据。对于我们的项目来说它提供了两大关键信息药物信息包括药物名称、化学结构SMILES、分类、作用机制等。靶点信息包括蛋白质名称、基因名、UniProt ID等。最关键的关系明确标注了哪些药物作用于哪些靶点。实际操作与数据获取访问DrugBank官网注册一个免费的研究账户即可下载数据集。我们主要需要两个文件drugbank_all_full_database.xml完整数据库或更易处理的drugbank_all_structures.sdf结构文件配合其他CSV关系表。然而直接解析XML或SDF对于新手来说有点复杂。一个更快捷的入口是使用DrugBank提供的公开数据集比如在Kaggle上就能找到用户上传的、已处理好的DrugBank CSV文件包含drugs.csvtargets.csv和drug_target_interactions.csv。这对于快速启动项目非常友好。注意使用任何公开数据务必遵守其使用许可协议License。DrugBank数据用于非商业学术研究通常是允许的但需要引用。数据预处理的关键步骤假设我们拿到了一个包含drug_id,drug_name,target_id,target_name,gene_name的交互表。原始数据往往很“脏”我们的预处理管道至少包含以下几步import pandas as pd import numpy as np # 1. 加载数据 interactions_df pd.read_csv(drug_target_interactions.csv) # 2. 去重同一对药物-靶点可能因数据来源不同而有重复记录 interactions_df interactions_df.drop_duplicates(subset[drug_id, target_id]) # 3. 处理缺失值检查关键字段是否有空值 print(interactions_df.isnull().sum()) # 如果drug_name或target_name缺失较多可以考虑用ID代替或从其他表关联补齐。 # 4. 统一标识符靶点通常使用标准的UniProt ID如‘P00734’最可靠。 # 检查target_id的格式如果不是UniProt ID可能需要通过基因名映射。 # 这里假设我们的target_id已经是UniProt ID。 # 5. 构建模型所需的矩阵将药物和靶点映射为连续的索引 all_drugs interactions_df[drug_id].unique() all_targets interactions_df[target_id].unique() drug_to_idx {drug: i for i, drug in enumerate(all_drugs)} target_to_idx {target: j for j, target in enumerate(all_targets)} interactions_df[drug_idx] interactions_df[drug_id].map(drug_to_idx) interactions_df[target_idx] interactions_df[target_id].map(target_to_idx) # 此时我们得到了一个干净的交互列表包含数字索引便于后续计算。这个预处理过程看似简单却决定了后续所有步骤的基石是否稳固。数据中的噪声和偏差会直接传递到模型中。3. 知识图谱构建用Neo4j描绘生物医学关系图有了干净的药物-靶点交互数据我们就可以构建知识图谱了。这里我选择Neo4j作为图数据库。它是一个高性能的NOSQL图形数据库使用Cypher查询语言非常直观特别适合存储和查询复杂的关联关系。为什么用图数据库而不用关系型数据库因为“关系”是这里的头等公民。我们不仅要存储“药物A作用于靶点B”这一事实未来还可能很容易地扩展加入“靶点B属于通路C”、“药物A有副作用D”、“疾病E与靶点B相关”等关系。在图数据库中查询“与药物A有相同靶点的所有其他药物”这样的问题效率极高且表达直观。这是传统关系型数据库通过多表JOIN难以优雅实现的。环境准备与Neo4j部署安装从Neo4j官网下载桌面版或社区服务器版。桌面版带图形化界面对初学者更友好。启动安装后启动Neo4j数据库它会默认在http://localhost:7474打开浏览器管理界面。默认用户名/密码是neo4j/neo4j首次登录会要求修改密码。Python连接使用neo4j官方Python驱动。pip install neo4j构建图谱的Python代码详解接下来我们将清洗好的数据导入Neo4j。核心是创建“药物”节点、“靶点”节点以及它们之间的“INTERACTS_WITH”关系。from neo4j import GraphDatabase class DrugTargetGraph: def __init__(self, uri, user, password): self.driver GraphDatabase.driver(uri, auth(user, password)) def close(self): self.driver.close() def create_drug_target_interaction(self, drug_id, drug_name, target_id, target_name): 创建单个药物-靶点交互关系 with self.driver.session() as session: # 使用MERGE确保节点不存在时创建存在时则匹配。避免重复创建。 query MERGE (d:Drug {drug_id: $drug_id}) ON CREATE SET d.name $drug_name MERGE (t:Target {target_id: $target_id}) ON CREATE SET t.name $target_name MERGE (d)-[r:INTERACTS_WITH]-(t) RETURN d.name, t.name result session.run(query, drug_iddrug_id, drug_namedrug_name, target_idtarget_id, target_nametarget_name) return result.single() def batch_create_interactions(self, interactions_df): 批量导入交互数据性能远优于单条插入 with self.driver.session() as session: # 将DataFrame转换为适合Neo4j参数的列表 records interactions_df[[drug_id, drug_name, target_id, target_name]].to_dict(records) # 使用UNWIND进行批量操作 query UNWIND $records AS record MERGE (d:Drug {drug_id: record.drug_id}) ON CREATE SET d.name record.drug_name MERGE (t:Target {target_id: record.target_id}) ON CREATE SET t.name record.target_name MERGE (d)-[:INTERACTS_WITH]-(t) session.run(query, recordsrecords) print(f成功导入 {len(records)} 条药物-靶点交互关系。) # 使用示例 uri bolt://localhost:7687 # Neo4j的Bolt协议端口 user neo4j password your_new_password # 替换成你修改后的密码 graph DrugTargetGraph(uri, user, password) # 假设interactions_df是预处理后的DataFrame包含drug_id,drug_name,target_id,target_name graph.batch_create_interactions(interactions_df) # 查询示例查找与特定靶点如‘P00734’相互作用的所有药物 def find_drugs_for_target(target_id): with graph.driver.session() as session: query MATCH (t:Target {target_id: $target_id})-[:INTERACTS_WITH]-(d:Drug) RETURN d.drug_id, d.name result session.run(query, target_idtarget_id) return [record for record in result] print(find_drugs_for_target(P00734)) graph.close()构建图谱时的核心技巧与避坑点务必使用MERGE而非CREATECREATE会无条件创建节点导致大量重复。MERGE是“有则匹配无则创建”保证了节点的唯一性。但要注意MERGE是对整个模式进行匹配确保你的匹配条件如{drug_id: $drug_id}能唯一确定一个节点。批量操作是必须的千万不要在循环中执行单条MERGE语句效率极低。使用UNWIND将数据列表作为参数传入让数据库一次性处理速度可能有数百倍的提升。索引是性能的关键在drug_id和target_id属性上创建索引能大幅加速MERGE和MATCH操作。这应该在导入数据之前完成。CREATE INDEX drug_id_index IF NOT EXISTS FOR (d:Drug) ON (d.drug_id); CREATE INDEX target_id_index IF NOT EXISTS FOR (t:Target) ON (t.target_id);内存管理导入大量数据时可能会遇到堆内存不足的问题。可以在Neo4j配置文件中调整dbms.memory.heap.initial_size和dbms.memory.heap.max_size或者将批量导入的批次大小调小。完成这一步后你就拥有了一个可视化的、可查询的药物-靶点关系网络。但这只是静态的知识库如何让它变得“智能”能进行预测呢这就需要推荐系统算法了。4. 推荐系统模型矩阵分解与深度学习的抉择将药物-靶点预测视为推荐问题我们有一个用户-物品评分矩阵R其中“用户”是靶点“物品”是药物“评分”是是否存在相互作用1表示已知作用0表示未知或暂无记录。但这个矩阵极其稀疏已知作用相对所有可能组合来说极少。我们的目标是补全这个稀疏矩阵预测那些“空白处”的值即未知的药物-靶点对是1可能作用的概率。这里我对比两种主流方法经典的矩阵分解和基于神经网络的深度学习模型。4.1 方法一隐语义模型与矩阵分解矩阵分解Matrix Factorization, MF是协同过滤的基石。其思想是将高维稀疏矩阵Rm个靶点 x n个药物分解为两个低维稠密矩阵的乘积R ≈ P * Q^T。其中P是靶点隐因子矩阵m x kQ是药物隐因子矩阵n x kk是隐因子维度通常远小于m和n。直观理解每个靶点可以用一个k维向量p_u表示其“偏好特征”每个药物用一个k维向量q_i表示其“属性特征”。预测靶点u对药物i的交互概率就是计算这两个向量的内积p_u · q_i。内积值越高表示靶点的偏好与药物的属性越匹配相互作用可能性越大。使用Surprise库实现Python的Surprise库专门用于构建和分析推荐系统内置了SVD奇异值分解一种矩阵分解方法等算法。from surprise import Dataset, Reader, SVD from surprise.model_selection import train_test_split from surprise import accuracy import pandas as pd # 1. 准备数据Surprise需要的数据格式是 (target_idx, drug_idx, rating) # 我们的‘rating’是二元的1有交互或 0无交互。但Surprise通常处理显式评分。 # 对于隐式反馈只有正样本1负样本未知我们需要负采样。 def prepare_implicit_data(interactions_df, num_negatives1): 为隐式反馈准备数据。 interactions_df: 包含drug_idx, target_idx的正样本DataFrame。 num_negatives: 为每个正样本采样的负样本数。 pos_samples interactions_df[[target_idx, drug_idx]].copy() pos_samples[rating] 1 # 负采样随机选择未观察到的target, drug对作为负样本 all_targets interactions_df[target_idx].unique() all_drugs interactions_df[drug_idx].unique() pos_pairs set(zip(interactions_df[target_idx], interactions_df[drug_idx])) neg_samples [] for target in all_targets: # 获取该靶点未交互的药物 interacted_drugs set(interactions_df[interactions_df[target_idx]target][drug_idx]) non_interacted_drugs list(set(all_drugs) - interacted_drugs) # 随机采样 if non_interacted_drugs: sampled_neg np.random.choice(non_interacted_drugs, sizemin(num_negatives, len(non_interacted_drugs)), replaceFalse) for drug in sampled_neg: neg_samples.append([target, drug, 0]) neg_df pd.DataFrame(neg_samples, columns[target_idx, drug_idx, rating]) all_data_df pd.concat([pos_samples, neg_df], ignore_indexTrue) return all_data_df # 生成带负样本的数据 implicit_data_df prepare_implicit_data(interactions_df, num_negatives3) # 2. 定义Reader和加载数据Surprise要求评分范围 reader Reader(rating_scale(0, 1)) data Dataset.load_from_df(implicit_data_df[[target_idx, drug_idx, rating]], reader) # 3. 划分训练集和测试集 trainset, testset train_test_split(data, test_size0.2, random_state42) # 4. 使用SVD算法矩阵分解 algo SVD(n_factors50, n_epochs20, lr_all0.005, reg_all0.02, random_state42) algo.fit(trainset) # 5. 预测与评估 predictions algo.test(testset) # RMSE, MAE对于0/1评分可能不是最佳指标但可用 rmse accuracy.rmse(predictions) mae accuracy.mae(predictions) # 6. 为特定靶点做Top-N药物推荐 def get_top_n_recommendations(algo, target_idx, drug_pool, n10): 为指定靶点推荐Top-N个最可能相互作用的药物。 drug_pool: 所有候选药物的索引列表。 # 预测该靶点对所有药物的评分 predictions [algo.predict(target_idx, drug_idx) for drug_idx in drug_pool] # 按估计评分降序排序 predictions.sort(keylambda x: x.est, reverseTrue) top_n predictions[:n] return [(pred.iid, pred.est) for pred in top_n] # 返回(药物索引预测评分) all_drugs_idx list(drug_to_idx.values()) top10_for_target_0 get_top_n_recommendations(algo, target_idx0, drug_poolall_drugs_idx, n10) print(f为靶点索引0推荐的Top-10药物: {top10_for_target_0})矩阵分解的优缺点优点模型简单可解释性相对较强隐因子可能对应某些生物化学特性计算效率高在稀疏数据上表现稳健。缺点本质上仍是线性模型难以捕捉药物和靶点之间复杂的非线性关系。特征需要手动设计或仅依赖ID无法利用药物结构如SMILES、靶点序列等丰富特征。4.2 方法二深度学习模型NeuMF架构为了克服MF的局限性我们可以引入深度学习。神经矩阵分解Neural Matrix Factorization, NeuMF是一个经典的混合模型它同时学习MF的线性部分和MLP多层感知机的非线性部分。模型思想MF部分和传统MF一样得到靶点隐向量p_u和药物隐向量q_i做内积p_u · q_i。MLP部分将p_u和q_i拼接起来输入到一个深度神经网络中。这个网络可以学习到p_u和q_i之间任意的非线性交互函数。融合将MF部分的输出和MLP部分的输出拼接最后通过一个全连接层映射到预测概率。使用PyTorch实现NeuMFimport torch import torch.nn as nn import torch.optim as optim from torch.utils.data import Dataset, DataLoader import numpy as np # 1. 定义数据集 class DrugTargetDataset(Dataset): def __init__(self, df, num_drugs, num_targets): self.targets torch.LongTensor(df[target_idx].values) self.drugs torch.LongTensor(df[drug_idx].values) self.ratings torch.FloatTensor(df[rating].values) self.num_drugs num_drugs self.num_targets num_targets def __len__(self): return len(self.ratings) def __getitem__(self, idx): return self.targets[idx], self.drugs[idx], self.ratings[idx] # 2. 定义NeuMF模型 class NeuMF(nn.Module): def __init__(self, num_targets, num_drugs, mf_dim8, mlp_layers[64, 32, 16], dropout0.2): super().__init__() # MF嵌入层 self.mf_target_embedding nn.Embedding(num_targets, mf_dim) self.mf_drug_embedding nn.Embedding(num_drugs, mf_dim) # MLP嵌入层 (维度通常比MF大以捕捉更多信息) self.mlp_target_embedding nn.Embedding(num_targets, mlp_layers[0]//2) self.mlp_drug_embedding nn.Embedding(num_drugs, mlp_layers[0]//2) # MLP部分 mlp_modules [] input_dim mlp_layers[0] # 两个嵌入向量拼接后的维度 for output_dim in mlp_layers[1:]: mlp_modules.append(nn.Linear(input_dim, output_dim)) mlp_modules.append(nn.ReLU()) mlp_modules.append(nn.Dropout(pdropout)) input_dim output_dim self.mlp_layers nn.Sequential(*mlp_modules) # 预测层 self.predict_layer nn.Linear(mf_dim mlp_layers[-1], 1) self.sigmoid nn.Sigmoid() # 初始化权重 self._init_weights() def _init_weights(self): for m in self.modules(): if isinstance(m, nn.Embedding): nn.init.normal_(m.weight, mean0.0, std0.01) elif isinstance(m, nn.Linear): nn.init.xavier_uniform_(m.weight) if m.bias is not None: nn.init.constant_(m.bias, 0) def forward(self, target_indices, drug_indices): # MF部分 mf_target_vec self.mf_target_embedding(target_indices) mf_drug_vec self.mf_drug_embedding(drug_indices) mf_output torch.mul(mf_target_vec, mf_drug_vec) # 逐元素相乘等价于内积的扩展 # MLP部分 mlp_target_vec self.mlp_target_embedding(target_indices) mlp_drug_vec self.mlp_drug_embedding(drug_indices) mlp_input torch.cat([mlp_target_vec, mlp_drug_vec], dim-1) mlp_output self.mlp_layers(mlp_input) # 融合 concat torch.cat([mf_output, mlp_output], dim-1) prediction self.predict_layer(concat) output self.sigmoid(prediction).squeeze() # 输出0-1之间的概率 return output # 3. 训练循环 def train_model(model, train_loader, val_loader, epochs20, lr0.001): device torch.device(cuda if torch.cuda.is_available() else cpu) model.to(device) criterion nn.BCELoss() # 二分类交叉熵损失 optimizer optim.Adam(model.parameters(), lrlr) for epoch in range(epochs): model.train() train_loss 0.0 for batch_targets, batch_drugs, batch_ratings in train_loader: batch_targets, batch_drugs, batch_ratings batch_targets.to(device), batch_drugs.to(device), batch_ratings.to(device) optimizer.zero_grad() outputs model(batch_targets, batch_drugs) loss criterion(outputs, batch_ratings) loss.backward() optimizer.step() train_loss loss.item() * batch_targets.size(0) avg_train_loss train_loss / len(train_loader.dataset) # 验证 model.eval() val_loss 0.0 with torch.no_grad(): for batch_targets, batch_drugs, batch_ratings in val_loader: batch_targets, batch_drugs, batch_ratings batch_targets.to(device), batch_drugs.to(device), batch_ratings.to(device) outputs model(batch_targets, batch_drugs) loss criterion(outputs, batch_ratings) val_loss loss.item() * batch_targets.size(0) avg_val_loss val_loss / len(val_loader.dataset) print(fEpoch {epoch1}/{epochs} - Train Loss: {avg_train_loss:.4f}, Val Loss: {avg_val_loss:.4f}) # 4. 数据准备与训练 from sklearn.model_selection import train_test_split train_df, val_df train_test_split(implicit_data_df, test_size0.1, random_state42) train_dataset DrugTargetDataset(train_df, num_drugslen(all_drugs), num_targetslen(all_targets)) val_dataset DrugTargetDataset(val_df, num_drugslen(all_drugs), num_targetslen(all_targets)) train_loader DataLoader(train_dataset, batch_size256, shuffleTrue) val_loader DataLoader(val_dataset, batch_size256, shuffleFalse) model NeuMF(num_targetslen(all_targets), num_drugslen(all_drugs), mf_dim16, mlp_layers[128, 64, 32]) train_model(model, train_loader, val_loader, epochs15, lr0.001)深度学习模型的优缺点优点模型容量大能学习复杂的非线性关系有潜力达到更高的预测精度。易于扩展可以很方便地将药物分子指纹、靶点序列特征等作为额外输入。缺点需要更多的数据以防止过拟合训练时间更长模型可解释性差是个“黑盒”超参数层数、维度、学习率等调优更复杂。如何选择如果你的数据集不大比如只有几千个已知交互计算资源有限且需要快速验证和可解释性从矩阵分解如Surprise的SVD开始是稳妥的选择。如果你的数据集规模可观数万以上交互并且你希望探索更高的预测上限不介意调参和更长的训练时间那么尝试NeuMF这类深度学习模型是值得的。你甚至可以进一步升级模型用图神经网络GNN直接在图结构Neo4j中的关系上进行学习这可能是更前沿的方向。5. 特征工程进阶融入药物与靶点的本体信息前面的模型只使用了药物和靶点的ID作为特征这丢失了大量宝贵的本体信息。一个更强大的模型应该能利用这些信息。例如药物特征可以从SMILES字符串计算分子指纹如ECFP4或使用预训练的分子表示模型如ChemBERTa得到向量。靶点特征可以从蛋白质序列通过UniProt ID获取计算氨基酸组成、理化性质或使用蛋白质语言模型如ESM得到嵌入向量。如何整合这些特征以NeuMF为例我们可以修改模型将额外的特征向量与原有的ID嵌入向量进行融合。class NeuMFWithFeatures(nn.Module): def __init__(self, num_targets, num_drugs, drug_feat_dim, target_feat_dim, mf_dim8, mlp_layers[64, 32, 16]): super().__init__() # ID嵌入层 self.mf_target_embedding nn.Embedding(num_targets, mf_dim) self.mf_drug_embedding nn.Embedding(num_drugs, mf_dim) self.mlp_target_embedding nn.Embedding(num_targets, mlp_layers[0]//2) self.mlp_drug_embedding nn.Embedding(num_drugs, mlp_layers[0]//2) # 特征处理层简单的全连接层用于降维或统一维度 self.drug_feat_layer nn.Linear(drug_feat_dim, mlp_layers[0]//2) self.target_feat_layer nn.Linear(target_feat_dim, mlp_layers[0]//2) # MLP部分输入维度变为 (mlp_id_embed feature_embed) * 2 mlp_input_dim mlp_layers[0] * 2 # 因为药物和靶点的ID嵌入与特征嵌入要拼接 mlp_modules [] input_dim mlp_input_dim for output_dim in mlp_layers[1:]: mlp_modules.append(nn.Linear(input_dim, output_dim)) mlp_modules.append(nn.ReLU()) mlp_modules.append(nn.Dropout(p0.2)) input_dim output_dim self.mlp_layers nn.Sequential(*mlp_modules) self.predict_layer nn.Linear(mf_dim mlp_layers[-1], 1) self.sigmoid nn.Sigmoid() self._init_weights() def forward(self, target_indices, drug_indices, target_features, drug_features): # MF部分仅基于ID mf_target_vec self.mf_target_embedding(target_indices) mf_drug_vec self.mf_drug_embedding(drug_indices) mf_output torch.mul(mf_target_vec, mf_drug_vec) # MLP部分融合ID和特征 mlp_target_id_vec self.mlp_target_embedding(target_indices) mlp_drug_id_vec self.mlp_drug_embedding(drug_indices) # 处理额外特征 mlp_target_feat_vec self.target_feat_layer(target_features) mlp_drug_feat_vec self.drug_feat_layer(drug_features) # 拼接ID嵌入和特征嵌入 mlp_target_concat torch.cat([mlp_target_id_vec, mlp_target_feat_vec], dim-1) mlp_drug_concat torch.cat([mlp_drug_id_vec, mlp_drug_feat_vec], dim-1) # 拼接靶点和药物的综合向量 mlp_input torch.cat([mlp_target_concat, mlp_drug_concat], dim-1) mlp_output self.mlp_layers(mlp_input) concat torch.cat([mf_output, mlp_output], dim-1) prediction self.predict_layer(concat) output self.sigmoid(prediction).squeeze() return output这样模型就能同时从交互历史协同过滤和药物/靶点自身的属性基于内容中学习预测能力通常会更强。获取这些特征需要借助其他工具库例如用RDKit计算分子指纹用Biopython或在线API获取蛋白质序列信息。6. 模型评估与结果解读不仅仅是AUC在二分类预测任务中我们不能只看损失函数下降。常用的评估指标包括准确率Accuracy、精确率Precision、召回率Recall、F1-score以及ROC曲线下面积AUC。对于高度不平衡的数据正负样本比例悬殊AUC通常是更稳健的指标。from sklearn.metrics import roc_auc_score, precision_recall_curve, auc, classification_report import torch def evaluate_model(model, data_loader): device next(model.parameters()).device model.eval() all_predictions [] all_labels [] with torch.no_grad(): for batch_targets, batch_drugs, batch_ratings in data_loader: batch_targets, batch_drugs, batch_ratings batch_targets.to(device), batch_drugs.to(device), batch_ratings.to(device) # 假设我们只有ID没有额外特征。如果有特征需要传入。 outputs model(batch_targets, batch_drugs) all_predictions.extend(outputs.cpu().numpy()) all_labels.extend(batch_ratings.cpu().numpy()) all_predictions np.array(all_predictions) all_labels np.array(all_labels) # 计算AUC auc_score roc_auc_score(all_labels, all_predictions) print(fROC-AUC Score: {auc_score:.4f}) # 计算PR-AUC (对于不平衡数据有时比ROC-AUC更敏感) precision, recall, _ precision_recall_curve(all_labels, all_predictions) pr_auc auc(recall, precision) print(fPR-AUC Score: {pr_auc:.4f}) # 选择一个阈值例如0.5计算分类报告 binary_predictions (all_predictions 0.5).astype(int) print(classification_report(all_labels, binary_predictions, target_names[Negative, Positive])) return auc_score, pr_auc # 在测试集上评估 # 需要先创建测试集的DataLoader test_dataset DrugTargetDataset(test_df, num_drugslen(all_drugs), num_targetslen(all_targets)) test_loader DataLoader(test_dataset, batch_size256, shuffleFalse) evaluate_model(model, test_loader)结果解读与验证得到一个不错的AUC分数比如0.85以上是一个好的开始但这远不是终点。对于药物发现而言可解释性和生物学合理性至关重要。Top-K预测分析查看模型为某个重要靶点如与癌症相关的激酶推荐的前10个药物。这些药物是已知的吗如果是已知的说明模型成功回忆起了知识。如果是未知的去查文献或数据库看是否有初步的生物学证据支持这能提供最直接的验证。案例分析选择一个模型高置信度预测的新相互作用对药物A-靶点B进行深入的文献调研和分子对接模拟这超出了本代码范畴但却是实际项目中的必要步骤。错误分析检查那些被模型错误预测的样本假阳性、假阴性。是否存在数据质量问题例如某些“负样本”在现实中其实是相互作用的只是尚未被实验发现或收录进数据库这能帮助你理解模型的局限性和数据的偏差。7. 项目总结与避坑指南回顾整个项目我们从数据获取、知识图谱构建到推荐系统模型的实现与评估完成了一个完整的AI辅助药物靶点预测流程。这个过程里我踩过不少坑也总结了一些关键经验核心避坑点数据质量是天花板DrugBank数据虽然好但也不完美。可能存在标注错误、遗漏或偏差。务必进行彻底的数据清洗和探索性分析EDA。考虑融合多个数据源如ChEMBL, BindingDB来增加数据的覆盖面和可靠性。负样本的定义是玄学我们采用随机采样的方式生成负样本但生物学上“未观测到相互作用”绝不等于“不相互作用”。这被称为“正未标记”Positive-Unlabeled, PU学习问题。更高级的做法是使用“负样本”挖掘策略比如选择那些与靶点空间距离很远的药物或者使用一些生物学上不可能结合的规则来生成“硬负样本”。评估指标的误导性在极度稀疏正样本极少的数据上即使AUC很高模型也可能只是学会了把所有样本都预测为负类。一定要结合精确率-召回率曲线PR Curve和Top-K的命中率Hit Ratio来综合判断。在测试集划分时务必确保每个靶点/药物在训练和测试集中都有出现即采用按用户/物品的分层抽样避免冷启动问题被掩盖。Neo4j导入性能导入百万级关系时如果一次性UNWIND一个巨大的列表可能会内存溢出。需要分批次提交每批几万条。使用apoc.periodic.iterate过程也是一种更专业的批量导入方法。深度学习模型过拟合由于数据量可能相对模型复杂度来说不够大过拟合是常态。务必使用早停Early Stopping、Dropout、权重衰减L2正则化等技术。同时简化模型结构减少层数、降低嵌入维度往往是第一个应该尝试的解决方案。可复现性设置随机种子np.random.seed(),torch.manual_seed()对于实验的可复现性至关重要。否则每次运行的负采样和模型初始化结果都会不同。未来扩展方向图神经网络GNN这是最自然的延伸。我们已经在Neo4j中构建了图可以直接使用PyTorch Geometric或DGL库将药物、靶点作为节点已知相互作用作为边让信息在图上传播从而学习更丰富的节点表示。这比独立的ID嵌入更能利用网络结构信息。多模态特征融合除了分子指纹和序列还可以引入药物的副作用、靶点的基因本体论GO注释、通路信息等构建一个更丰富的知识图谱并设计更复杂的多模态融合模型。主动学习与湿实验验证将模型部署为一个持续学习的系统。将模型预测的高置信度新相互作用提交给生物学家进行湿实验验证然后将验证结果无论是正例还是反例作为新数据反馈给模型形成一个闭环不断提升模型的实用性和可靠性。这个项目就像搭积木本文提供了最核心的几块积木和搭建方法。你可以根据自己的需求和兴趣更换更优质的数据源积木尝试更先进的模型架构搭建方式最终构建出属于你自己的、更强大的药物发现辅助工具。希望这份详细的指南和代码能为你节省大量摸索的时间直接切入到最有价值的探索环节中去。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门