2. 蛋白-配体预测基础:常见数据集介绍、分子表示(指纹/图表征)、评估指标

好,咱们正式开始聊技术细节。搞蛋白-配体预测,说白了就是回答一个问题:这个小分子和这个蛋白能不能结合,结合得有多牢。这个问题要是搁在十年前,大家更多是靠分子对接和力场打分。但现在深度学习介入后,数据驱动成了主流。所以,数据长什么样,特征怎么提,模型好不好——这三件事就是地基。这一章我就把这三个基础桩子给你打牢。

核心观点: 蛋白-配体预测的成败,80%取决于数据质量和特征表示,剩下20%才是模型结构。别一上来就调Transformer,先看看你的数据干不干净,特征有没有丢关键信息。

2.1 常见数据集:你手头有哪些资源?

做这个领域,你绕不开的几个数据集,我来给你列一列。我个人习惯先弄清楚数据集的规模、分辨率、冗余度三个属性,再去选。

数据集 类型 规模(约) 特点 典型用途
PDBbind 实验结合亲和力 ~19,000 复合物 来自PDB,有高精度Kd/Ki值;版本v2016/v2020常用 回归任务(预测pKd/pKi)
BindingDB 实验结合亲和力 ~2,000,000 数据点 数据量大但噪声高;包含多种测量条件 大规模预训练、对比学习
DUD-E / DEKOIS 虚拟筛选基准 ~100 靶点 精心设计的非活性类似物(decoys);化学空间匹配好 分类任务(活性vs非活性)
MCSA / PDBbind-CNF 卷积/图网络基准 ~4,000 复合物 去冗余、结构多样性可控 模型对比、消融实验

这里我插一句。PDBbind里v2016到v2020版本变化很大,早期版本里晶体结构分辨率差的不在少数。我曾经在一个项目中直接拿v2016裸跑,结果模型在测试集上炫得眼花缭乱,一换到新版本就崩了。查了半天,原来是训练集里好几个复合物原本就是同一个蛋白的同源结构重组,存在严重的数据泄漏。所以,数据去冗余是第一步,建议用BLAST或MMseqs2把序列相似度30%以上的全去掉。

2.2 分子表示:指纹 vs 图表征

特征表示这件事,嗯,说白了就是把化学结构变成数字给模型吃。目前主流两条路:分子指纹和分子图。两派都有拥趸,我个人在工业项目里是混着用的。

2.2.1 分子指纹

指纹是"固定长度向量",每个维度对应一个子结构是否存在。我最常用的是ECFP(Extended Connectivity Fingerprint)。

# 用RDKit计算ECFP4指纹
from rdkit import Chem
from rdkit.Chem import AllChem

mol = Chem.MolFromSmiles('CC(=O)OC1=CC=CC=C1C(=O)O')  # 阿司匹林
fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=2048)

# 转换成numpy数组
import numpy as np
arr = np.array(fp)
print(arr.shape)  # (2048,)
print(arr.sum())  # 看看多少个"1"
我的一点经验:指纹维度的选择有讲究。nBits=1024在中小规模数据上够用,但如果你做虚拟筛选,库里有几百万分子,我建议升到2048或4096。太低会出现碰撞(两个不同分子撞出同一个向量),太高则稀疏度过大,模型学不动。

指纹的好处是快、稳、好解释。但老实说,它丢失了原子之间的连接顺序和三维构象信息。图表征就是来解决这个问题的。

2.2.2 图表征

分子图把原子看作节点,化学键看作边。节点属性可以是原子类型、杂化状态、电荷、是否在环上等;边属性可以是键级、是否为芳香键等。这种表示天然适合GNN(图神经网络)来吃。

举个例子,用DGL构建一个简单的分子图:

import dgl
import torch
from rdkit import Chem

def mol_to_graph(mol):
    atoms = mol.GetAtoms()
    node_feats = []
    for atom in atoms:
        # 原子类型:C、N、O、S、P... one-hot编码
        atom_type = atom.GetAtomicNum()
        # 简化处理,实际要用更多特征
        node_feats.append([atom_type > 0])  # 假特征

    edges = []
    for bond in mol.GetBonds():
        start = bond.GetBeginAtomIdx()
        end = bond.GetEndAtomIdx()
        edges.append((start, end))
        edges.append((end, start))  # 无向图

    src, dst = zip(*edges) if edges else ([], [])
    g = dgl.graph((torch.tensor(src), torch.tensor(dst)))
    g.ndata['feat'] = torch.tensor(node_feats, dtype=torch.float32)
    return g

图表征的核心优势在于它能感知局部化学环境。但缺点也很明显:图同构问题。同一个分子可能有多个图表示(比如原子编号顺序不同、键表顺序不同)。GNN如果不加注意,可能把这些视为不同的样本,导致模型不稳定。

避坑指南:我曾经在训练一个GNN模型时,发现同一个分子在两次前向传播中得到的嵌入向量不一样,起初百思不得解。后来发现是图构建时边列表的顺序没有固定,DGL的message passing受到了影响。解决方案是:对节点和边按照规范顺序(例如按原子序号、键类型)排序,保证确定性。

2.3 评估指标:怎么才算好?

模型做出来了,总得有个客观标准来衡量。不同任务类型看不同的指标,我按场景分开说。

2.3.1 回归任务:预测结合亲和力

这类任务最常见。指标也简单直接:

  • RMSE:均方根误差,单位是pKd或pKi。实战中RMSE < 1.0算可用,< 0.5就算优秀。但要注意,不同数据集的RMSE不直接可比,因为测量误差范围不一样。
  • R²:决定系数,衡量模型解释了多大方差。R² > 0.6一般就算不错了。但我遇到过R²高达0.9但实际预测一塌糊涂的情况——数据泄漏做的妖。
  • Pearson相关系数:看趋势,不要求绝对准。工业应用中我常看这个,因为药物化学家更关心排名而非具体值。

2.3.2 分类任务:活性 vs 非活性

分类指标你肯定熟悉:

指标 计算公式 关注点
AUC-ROC ROC下方面积 整体排序能力,不依赖阈值
F1-score 2 * (Prec * Rec) / (Prec + Rec) 平衡精确率与召回率
Enrichment Factor 前1%命中率 / 背景命中率 虚拟筛选中最看重,模拟实际筛选流程
BEDROC 基于排序的富集度 早期富集能力,适合筛选场景
我对指标选择的建议:如果你做的是虚拟筛选落地项目,别只盯着AUC-ROC。AUC高不代表你的模型在最前面的分子里能抓到活性物。去看看Enrichment Factor at 1%和BEDROC,这两个指标更贴近实际场景。我见过太多AUC > 0.95的模型,一拉列表发现前100个全是假阳性。

2.3.3 为什么过拟合在这些指标上特别隐蔽?

你想想看,训练集和测试集如果存在同源蛋白共享配体或同一配体多次出现,模型可能不需要学真正的物理化学规律,只需要记住训练集中的"答案"。这导致RMSE和AUC在测试集上都好看,但一到全新靶点就崩。

所以,咱们这套课程的核心主题——数据增强,本质上就是强迫模型去学普适规律,而不是死记硬背。

我的实战体会:在Check做验证时,建议做严格的时间分裂或蛋白序列聚类分裂。比如用2018年之前的PDB数据训练,2019年之后的数据做测试。这样得到的评估分数才真正反映了模型的泛化能力,而不是代码层面的巧合。

好了,基础的三板斧:数据集、分子表示、评估指标,我已经给你拆解清楚了。接下来我们会在这个地基上,挨个儿看数据增强如何帮我们解决那些顽固的过拟合问题。

蛋白-配体预测基础 🧠 知识图谱 蛋白-配体预测 常见数据集 PDBbind BindingDB DUD-E / DEKOIS 分子表示 分子指纹 图表征 ECFP4/6 DGL Graph 评估指标 RMSE / R² AUC-ROC / F1 EF / BEDROC 数据增强是贯穿三条线的桥梁 ❓ 数据不够?增强合成复杂度 → ❓ 指纹/图不够鲁棒?增强扰动 → ❓ 指标虚高?增强对抗过拟合