4. 分子表征与特征工程

毒性预测模型的性能上限,往往在特征工程阶段就已经被决定。同一个随机森林或图神经网络,输入不同的分子表征,AUC 可能相差 0.15 以上。本节围绕“把分子变成模型可读的数值向量”这一核心任务,梳理四类主流表征方式及其适用边界,并给出面向毒性预测的特征选择与验证流程。

一、四类分子表征的本质差异

分子指纹是基于子结构的哈希或计数向量。以 Morgan/ECFP 为例,算法从每个重原子出发,按半径 r 迭代扩展邻域,将每层子结构哈希到固定长度位串(如 2048 位)。r=2 对应直径 4 的邻域,能捕捉官能团级别的局部环境。MACCS Keys 则是 166 位预定义子结构字典,可解释性强但覆盖有限。指纹的优点是计算快、对局部毒性基团(如硝基、环氧化物、酰卤)敏感;缺点是丢失立体化学与长程拓扑信息。

分子描述符是可解释的物理化学量。RDKit 的 Descriptors 模块可计算约 200 个描述符,毒性建模中高频使用的包括:MolWt(分子量)、MolLogP(脂水分配系数)、TPSA(拓扑极性表面积)、NumHDonors/NumHAcceptors(氢键供受体数)、NumAromaticRings(芳环数)、FractionCSP3(sp³ 碳比例)、MaxPartialCharge(最大部分电荷)。这些量直接关联 ADMET 性质:LogP > 5 且 TPSA < 75 的化合物更易穿透生物膜并蓄积,肝毒性风险上升;FractionCSP3 偏低常与 hERG 抑制相关。

图表示把分子视为原子为节点、化学键为边的属性图。节点特征通常为原子类型、度、形式电荷、杂化方式、是否在环内;边特征为键型(单/双/三/芳香)、是否共轭、是否在环内。GNN 通过消息传递聚合邻域信息,天然保留拓扑与立体信息,适合捕捉“毒性由特定子图组合触发”的模式,但需要更多数据且可解释性弱于描述符。

SMILES 嵌入将一维字符串映射为连续向量。早期用字符级 n-gram 或 TF-IDF,现在多用预训练语言模型(如 ChemBERTa、MolFormer)或 SMILES 枚举增强。其优势是能利用大规模无标注数据,对训练集未出现的骨架有一定泛化;风险是嵌入空间缺乏化学约束,可能出现“相似向量、迥异结构”的伪相似。

分子表征 → 特征工程 → 毒性预测 数据流 分子输入 SMILES / SDF CC(=O)Oc1ccccc1C(=O)O ① 分子指纹 Morgan/ECFP r=2, 2048 bit MACCS 166 bit 局部子结构 · 快 · 可解释 ② 分子描述符 MolLogP, TPSA, MolWt NumHDonors, FractionCSP3 物理化学量 · 强可解释 ③ 图表示 节点: 原子类型/电荷/杂化 边: 键型/共轭/环 拓扑完整 · 需数据 · 黑箱 ④ SMILES 嵌入 ChemBERTa / MolFormer 特征融合 拼接 / 加权 标准化 (Z-score) 缺失值填充 特征选择与降维 方差过滤 (低方差剔除) 相关性过滤 (|r| > 0.95) RF 重要性 / 递归消除 L1 正则稀疏化 PCA / UMAP 降维 目标: 保留毒性信号 剔除冗余与噪声 提升泛化与可解释性 毒性预测模型 RF / XGBoost / GNN / MLP 输出: 毒性概率 + 置信区间 交叉验证反馈 · 特征重要性回看

二、面向毒性预测的特征选择实操

把四类表征简单拼接会得到数千维特征,直接训练极易过拟合。以下流程以“肝毒性二分类”为例,训练集 1200 个化合物、测试集 300 个,正负比约 1:3。

第一步:方差与缺失过滤。剔除方差接近 0 的位(如所有分子都不含某子结构)和缺失率 > 20% 的描述符。RDKit 计算的部分描述符在含金属原子时可能返回 NaN,需显式处理。

第二步:相关性去冗余。计算描述符间 Pearson 相关系数,对 |r| > 0.95 的特征对,保留与标签互信息更高者。例如 MolWt 与 NumHeavyAtoms 高度相关,通常保留 MolWt。

第三步:基于模型的重要性排序。用随机森林(500 棵树,max_depth=12)拟合,输出 feature_importances_。典型结果中,MolLogP、TPSA、NumAromaticRings、Morgan 指纹中对应“芳香胺/硝基”的位往往排在前列。取重要性累计贡献 95% 的特征子集。

第四步:递归特征消除(RFE)与交叉验证。以 5 折交叉验证的 AUC 为准则,逐步剔除最不重要特征。示例中,从 2048+200 维降至约 180 维时,验证集 AUC 从 0.78 升至 0.84;继续降至 50 维以下则 AUC 回落,说明存在信息损失。

from rdkit import Chem
from rdkit.Chem import AllChem, Descriptors
import numpy as np

def featurize(smiles):
    mol = Chem.MolFromSmiles(smiles)
    if mol is None:
        return None
    # Morgan 指纹 2048 位
    fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=2048)
    fp_arr = np.array(fp)
    # 关键描述符
    desc = np.array([
        Descriptors.MolWt(mol),
        Descriptors.MolLogP(mol),
        Descriptors.TPSA(mol),
        Descriptors.NumHDonors(mol),
        Descriptors.NumHAcceptors(mol),
        Descriptors.NumAromaticRings(mol),
        Descriptors.FractionCSP3(mol),
    ])
    return np.concatenate([fp_arr, desc])

# 示例: 对乙酰氨基酚
vec = featurize("CC(=O)Nc1ccc(O)cc1")
print(vec.shape)  # (2055,)

三、表征选择与验证的判断依据

选择哪类表征,取决于数据规模、可解释性要求和毒性终点。数据量 < 500 时,优先描述符 + MACCS,避免 GNN 过拟合;数据量 > 5000 且毒性机制涉及复杂子图组合时,图表示或 SMILES 嵌入更有优势。若监管场景要求解释“为什么预测有毒”,描述符和指纹位可直接映射到官能团,而 GNN 需借助 GNNExplainer 等事后解释工具。

验证环节必须使用骨架划分(scaffold split)而非随机划分。随机划分会让同一骨架的类似物同时出现在训练和测试集,导致 AUC 虚高。以 Bemis-Murcko 骨架分组后,测试集 AUC 通常比随机划分低 0.05~0.12,这个差值才是模型真实泛化能力的体现。

实操建议:先用描述符 + Morgan 指纹建立基线模型,记录 scaffold split 下的 AUC 与 PR-AUC;再尝试图表示或预训练嵌入,只有当基线提升 > 0.03 且交叉验证稳定时才替换。毒性预测中正样本稀少,PR-AUC 比 ROC-AUC 更能反映实际筛选能力。
常见陷阱:对全量数据做标准化后再划分训练/测试集,会造成信息泄漏。正确做法是在训练集上拟合 StandardScaler,再 transform 测试集。指纹位为 0/1 变量,通常无需标准化,但描述符必须处理量纲差异。