2. 数据质量与预处理实战
在ADMET建模中,模型的上限往往不由算法决定,而由数据质量决定。一个化合物在实验中被记录为“溶解度低”,另一个被记录为“不溶”,第三个干脆缺失该字段——如果直接把这些记录喂给模型,模型学到的不是化学规律,而是数据录入习惯。本节围绕一条真实可执行的数据预处理流水线展开:从原始ADMET数据表出发,依次完成结构标准化、重复结构去重、缺失值处理、异常值检测与数据清洗,最终得到可用于建模的干净数据集。
一、先明确“脏”在哪里:ADMET数据的典型质量问题
ADMET数据通常来自多个来源:企业内部实验记录、公开数据库(如ChEMBL、PubChem)、文献补充材料。常见问题包括:
- 结构表示不统一:同一分子可能以SMILES、InChI、InChIKey或图片形式存在,且SMILES存在芳香性、互变异构、盐形式、立体化学等差异。
- 重复结构:同一化合物因不同盐型、不同立体异构体或不同数据来源被重复记录。
- 缺失值:某些端点(如hERG、CYP3A4抑制)只有部分化合物有实验值。
- 异常值:单位换算错误、数量级错误、实验操作失误导致的极端值。
- 单位与量纲不一致:logP、logD、pIC50、IC50(nM/μM)混用。
这些问题如果不处理,会直接导致模型在训练集上表现良好、在外部验证集上崩溃。下面给出一条可复现的预处理流程,并用一张关系图展示各步骤之间的依赖与数据流向。
二、结构标准化:让同一分子只有一个“身份证”
结构标准化是后续所有步骤的基础。推荐使用RDKit完成以下操作:
from rdkit import Chem
from rdkit.Chem import SaltRemover, rdMolStandardize
def standardize_smiles(smi):
mol = Chem.MolFromSmiles(smi)
if mol is None:
return None
# 1. 去盐
remover = SaltRemover.SaltRemover()
mol = remover.StripMol(mol, dontRemoveEverything=True)
# 2. 中和电荷
uncharger = rdMolStandardize.Uncharger()
mol = uncharger.uncharge(mol)
# 3. 标准化互变异构体
enumerator = rdMolStandardize.TautomerEnumerator()
mol = enumerator.Canonicalize(mol)
# 4. 生成规范SMILES
return Chem.MolToSmiles(mol, isomericSmiles=True)
# 示例
print(standardize_smiles("CC(=O)[O-].[Na+]")) # 输出 CC(=O)O
标准化后,用InChIKey作为唯一结构标识。InChIKey的前14位表示骨架连接性,后10位表示立体化学和同位素信息。对于ADMET建模,通常以前14位作为去重主键,保留立体化学信息用于后续分析。
三、重复结构去重:不只是“删掉一样的”
重复结构有三种典型情况:
- 完全重复:InChIKey完全相同,直接保留一条。
- 盐型/溶剂化物重复:标准化后InChIKey相同,但原始记录不同,保留实验值最完整的一条。
- 近似重复:骨架相同、取代基不同,需通过骨架聚类或相似度阈值(如Tanimoto > 0.85)识别,避免训练集与测试集泄漏。
实操中建议先按InChIKey去重,再用Butina聚类或Murcko骨架分组,检查是否存在“同一骨架多个类似物”被分到不同集合的情况。如果发现,应在划分训练/测试集时按骨架分组,而不是按分子随机划分。
四、缺失值处理:删除、插补还是掩码?
ADMET数据缺失通常不是随机的。例如,hERG实验往往只对高风险化合物做了测试,导致缺失与活性相关。处理策略取决于缺失比例和缺失机制:
| 缺失比例 | 推荐策略 | 注意事项 |
|---|---|---|
| <5% | 删除缺失样本 | 检查删除后是否引入分布偏移 |
| 5%–40% | 中位数/KNN/迭代插补 | 插补后增加“是否插补”指示变量 |
| >40% | 弃用该端点或单独建模 | 避免用大量插补值训练模型 |
| 分类端点 | 单独设“未知”类 | 不要用众数填充后当作真实标签 |
对于多端点联合建模,还可以使用掩码机制:在损失函数中只计算有观测值的端点,缺失位置不参与梯度更新。这种方式比插补更保守,适合缺失比例较高的场景。
五、异常值检测:先标记,再判断
异常值检测常用三种方法:
- Z-score:适用于近似正态分布,|Z| > 3 标记为异常。
- IQR:适用于偏态分布,超出 Q1−1.5×IQR 或 Q3+1.5×IQR 标记。
- 模型残差:用简单模型(如随机森林)预测,残差超过阈值标记。
关键原则是:异常值不等于错误值。例如,某个化合物的logD异常高,可能是真实的强亲脂性分子,也可能是单位写错。必须结合化学合理性复核:检查分子量、logP预测值、结构警示子,判断是否合理。只有确认是录入或单位错误时才删除,否则应保留并标记,供后续适用域分析使用。
六、数据清洗与标准化:单位、量纲与格式统一
最后一步是把所有端点值统一到可比较的尺度。常见操作包括:
- IC50/EC50统一转换为pIC50 = −log10(IC50[M]),避免nM/μM混用。
- logP、logD保留原始对数值,注意实验条件(pH)是否一致。
- 分类端点统一为0/1或0/1/2(如无、弱、强)。
- 所有数值保留一致的有效数字,避免浮点误差。
完成以上步骤后,得到的数据集应满足:结构唯一、单位统一、缺失值有明确处理策略、异常值有标记和复核记录。这样的数据集才能支撑后续的ADMET模型训练与适用域评估,也才能让模型真正学到化学规律,而不是数据噪声。