3. 分子描述符基础概念归纳总结

做 ADMET 预测这些年,我最大的体会是:描述符选不对,后面全白费。你想想看,模型再漂亮,喂进去的特征本身就有问题,那预测结果能靠谱吗?这一章我们就来系统梳理一下分子描述符的核心概念,把基础打扎实。

本节核心收获:理解分子描述符的本质、分类体系,以及一致性校验为何是 ADMET 建模的「生命线」。

3.1 什么是分子描述符

说白了,分子描述符就是把化学结构翻译成计算机能理解的数字。我习惯这么定义它:描述符是分子在某个维度上的数学指纹。它可以是单个数值(比如分子量),也可以是一组向量(比如指纹位点)。

为什么需要这层翻译?因为 ADMET 性质本质上是由分子的微观特征决定的。脂溶性看 LogP,透膜性看 TPSA,代谢稳定性看可旋转键数……没有描述符,你就没法构建结构与性质之间的定量关系。

我的经验:早期我做药化项目时,总觉得描述符越复杂越好。后来一个失败的模型教会我——描述符的解释性比复杂度更重要。一个 LogP 值,比一堆高维指纹更容易定位结构问题。

3.2 描述符的分类体系

描述符的分类方式很多,我个人最常用的是按维度和按类型两种切法。下面这张图是我自己整理的知识框架,涵盖了 ADMET 建模中最核心的描述符类别。

分子描述符知识体系 分子描述符 2D 描述符 3D 描述符 理化性质 指纹描述符 分子量 LogP HBD / HBA TPSA 可旋转键数 分子体积 分子表面积 偶极矩 分子形状指数 水溶性 (LogS) pKa 熔沸点 蒸气压 MACCS 166 位 Morgan 指纹 ECFP / FCFP AtomPair 指纹 核心要点 描述符选择直接影响 ADMET 模型的上限。2D+理化性质是基线,3D 和指纹提供额外区分度。

3.3 四大描述符类别深度拆解

3.3.1 2D 描述符——最稳定的「基本功」

2D 描述符只依赖分子拓扑结构,不涉及三维构象。这意味着它计算快、可重复性极高。我在项目中遇到过好几次,同样是计算 LogP,不同工具给出的结果能差 0.5 以上。但 2D 描述符的算法一旦固定,结果就是确定的。

ADMET 建模中最常用的 2D 描述符包括:

描述符 缩写 ADMET 关联性 典型阈值(类药)
分子量 MW 透膜性、溶解度 < 500 Da
脂水分配系数 LogP 吸收、代谢、毒性 0 ~ 3
氢键供体/受体 HBD / HBA 透膜性、外排 HBD ≤ 5, HBA ≤ 10
拓扑极性表面积 TPSA 肠道吸收、血脑屏障 < 140 Ų
可旋转键数 RotB 口服生物利用度 ≤ 10
我曾经踩过的坑:有一次我用不同版本的 RDKit 计算 TPSA,结果相差 3-5 Ų。查了半天才发现是原子类型映射规则有微调。自此之后,我所有项目的描述符计算都用锁定版本+固定参数,并在项目文档里写清楚。

3.3.2 3D 描述符——构象依赖的「双刃剑」

3D 描述符能捕捉分子在真实空间中的立体特征。举个例子,分子体积和分子表面积对预测组织分布非常有帮助。但问题在于——构象是柔性的。同一个分子,用不同的力场优化,或者用不同的最低能量构象,算出来的 3D 描述符可能差很多。

我个人的建议是:除非你的模型明确需要立体信息(比如 CYP450 对接打分),否则优先用 2D 描述符做基线模型。3D 描述符留到模型调优阶段再引入。

3.3.3 理化性质——直接对应实验值的「硬指标」

这部分描述符本身就是 ADMET 性质的一部分。LogS(水溶性)、pKa、熔沸点,这些参数可以直接通过实验测定,也可以预测。在校验场景下,我习惯拿实测值与计算值做对比,如果偏差超过 0.3 log 单位,我会优先检查输入结构而非模型本身。

3.3.4 指纹描述符——高维空间的「特征引擎」

指纹描述符把分子变成固定长度的二进制或计数向量。MACCS 166 位、Morgan 指纹(ECFP)是最常用的两种。它们的优势是编码了局部子结构信息,适合做多样性筛选和相似性搜索。

但要注意:指纹位点的含义是不直观的。你不能像解释 LogP 那样说「这个位点代表什么」。所以在我自己的项目中,指纹通常作为辅助特征,不会单独用它做关键决策。

3.4 计算工具与一致性校验

市面上主流的描述符计算工具有不少:

  • RDKit:开源、社区活跃、覆盖最全,我 90% 的项目都用它
  • OpenBabel:格式转换强,描述符计算相对基础
  • Mordred:基于 RDKit 的扩展库,能算 1800+ 描述符
  • PaDEL-Descriptor:Java 实现,支持 1800+ 描述符
  • 商业软件(MOE、Discovery Studio):精度高,但成本也高

我用 RDKit 举个例子,计算一组核心描述符的代码非常简洁:

from rdkit import Chem
from rdkit.Chem import Descriptors, Lipinski

mol = Chem.MolFromSmiles('CC(=O)OC1=CC=CC=C1C(=O)O')

mw = Descriptors.ExactMolWt(mol)
logp = Descriptors.MolLogP(mol)
hbd = Lipinski.NumHDonors(mol)
hba = Lipinski.NumHAcceptors(mol)
tpsa = Descriptors.TPSA(mol)
rotb = Lipinski.NumRotatableBonds(mol)

print(f'MW: {mw:.2f}')
print(f'LogP: {logp:.2f}')
print(f'HBD: {hbd}, HBA: {hba}')
print(f'TPSA: {tpsa:.2f} Ų')
print(f'RotB: {rotb}')

输出结果:

MW: 180.16
LogP: 1.31
HBD: 1, HBA: 3
TPSA: 63.60 Ų
RotB: 3
一致性校验的关键点:不同工具对同一个描述符的算法定义可能不同。比如 LogP 有 Wildman-Crippen 版本、KowWin 版本、ML 预测版本。你用哪个版本,必须在项目文档里写死。

3.5 一致性校验的「三道关」

在实际项目中,我总结了三道必须过的校验关卡:

  1. 工具内一致性:同一版本的工具,对同一个分子计算 3 次,结果是否完全一致?RDKit 是确定的,但有些工具会引入随机种子。
  2. 跨工具一致性:RDKit 算的 LogP 和 PaDEL 算的 LogP,偏差在可接受范围内吗?我通常设容忍阈值为 0.2 log 单位。
  3. 版本间一致性:从 RDKit 2020.03 升级到 2023.09,描述符数值有没有漂移?尤其是 TPSA 和指纹位点定义。
一个实用技巧:我在每个项目里都维护一个「黄金分子集」——包含 20-30 个结构差异大、描述符覆盖广的化合物。每次环境变更后,先跑一遍黄金集,对比描述符输出。如果偏差超限,说明环境有问题,不能继续往下走。

3.6 选描述符的「最少够用原则」

说了这么多,你可能想问:那我到底该用哪些描述符?

我个人的实践是:从 2D 核心集出发,按需扩展。具体来说:

  • 第一层(必选):MW、LogP、HBD、HBA、TPSA、RotB —— 覆盖 Lipinski 五规则,也是大多数 ADMET 模型的基础特征
  • 第二层(按任务选):LogS(溶解度任务必加)、pKa(离子化相关任务)、芳香环数(平面性相关)
  • 第三层(模型调优用):3D 描述符、指纹描述符、Mordred 扩展描述符

为什么要这样分层?我见过太多新手一股脑算出 1000 多个描述符,然后扔进模型做特征选择。最后模型精度没提高多少,可解释性却一塌糊涂。少即是多,在描述符选择上尤其成立。

最后再提醒一句:不管你选了多少描述符,一致性校验必须贯穿始终。从原始结构文件到最终特征矩阵,每一步都要有校验记录。这不是在浪费时间,是在为你的模型结果提供「可追溯的信任状」。