多批次ADMET数据来源与格式归纳总结

接手过几套不同来源的ADMET数据后,我最大的体会是——数据长什么样,决定了你后续要花多少力气去洗。有的批次来自实验记录表,有的从公共数据库扒下来,还有的是从文献里一行一行手动摘的。格式五花八门,SMILES、SDF、CSV、JSON……光是看后缀就能让人头大。这一节咱们就把这些「来路」和「长相」理清楚。

数据来源:三大主流渠道

ADMET数据的来源,说白了就三种路数。我按自己踩过的坑排了个序,从最省心到最折腾。

来源类型典型代表数据量级格式干净度
公开数据库ChEMBL、PubChem、DrugBank百万级★★★★☆ 结构较规整
自建实验平台HTS筛选、ADMET assay平台百到千级★★★☆☆ 依赖实验记录规范
文献挖掘论文补充材料、专利表格几十到几百★★☆☆☆ 碎片化、单位不一致
我的经验:虽然公开数据库下载很方便,但同一个化合物在不同库里的SMILES可能不一样,甚至手性标记都缺。我在整合ChEMBL和PubChem时就翻过车——看似相同的分子,标准化后才发现互变异构体没对齐。

数据格式:五种常见“壳”

不管你从哪拿数据,最终都会落到下面五种格式之一。我个人习惯把它们分成「结构化」和「半结构化」两类。

  • CSV/TSV —— 最通用的表格格式,列标题通常为 SMILES, logD, pKa, HLM_Clint 等。注意:SMILES 列里可能有逗号或引号,要正确转义。
  • SDF (Structure Data File) —— 化学信息学传统格式,每个分子有原子坐标 + 属性块。适合存三维结构,但属性值读取稍麻烦。
  • JSON —— 现代API下载时常用,嵌套结构里可能混着数组和字典。比如 {"molecule": "CC(C)=O", "properties": {"logD": 0.8, "source": "PubChem"}}。
  • XML —— 老派一些的数据库(如DrugBank)还在用,标签层级深,解析代码容易写长。
  • 纯文本/SMILES列表 —— 文献里最常见,一个文件里一行一个SMILES,附一个数值。格式极简,但缺失元数据。

格式对比:一眼看出差异

格式解析难度属性承载能力标准化推荐度
CSV★☆☆☆☆ 简单中等★★★★★ 首选统一格式
SDF★★★☆☆ 中等高(含结构)★★★☆☆ 结构保留用
JSON★★☆☆☆ 简单高★★★★☆ 程序友好
XML★★★☆☆ 中等高★★☆☆☆ 近年来用得少
纯文本★☆☆☆☆ 极简极低★★☆☆☆ 仅临时使用
避坑指南:我曾经拿到一个批次的数据,所有SMILES列都用双引号包裹,但双引号内部又出现了未转义的引号。结果pandas.read_csv直接崩了。解决办法是传 quoting=csv.QUOTE_ALL,或者指定 escapechar='\\'。

数据来源与格式的关系图

下面这张图梳理了常见数据源和它们输出的格式,以及我建议的标准化路径。你拿到新批次后,可以照着这个流程图快速定位。

多批次ADMET数据来源与格式关系图 公开数据库 自建实验平台 文献挖掘 SDF / JSON / XML CSV / 实验专用格式 纯文本 / PDF表格截图 标准化CSV / 统一SMILES 数据标准化要点 • 所有原始格式最终转换为CSV,含3列:SMILES、Property、Value、Source • 使用 rdkit.Chem.MolFromSmiles 统一标准化SMILES符号 • 实验数据附加单位列(如 logD @ pH7.4 vs logD @ pH6.5) 公开数据库 自建实验 文献挖掘
核心原则:不管你拿到的原始格式多冷门,最终都归一成 CSV + 标准化SMILES。这一步做扎实了,后面所有脚本、模型、数据库入库才能统一处理。

实际操作:把SMILES标准化先做掉

拿到数据后第一件事不是看数值,而是检查SMILES。我踩过的坑里,至少有一半是因为SMILES没对齐导致重复或漏算。下面是个简单的标准化脚本片段,你可以放在数据预处理的第一步。

from rdkit import Chem
from rdkit.Chem import MolFromSmiles, MolToSmiles

def standardize_smiles(smiles):
    mol = MolFromSmiles(smiles)
    if mol is None:
        return None
    # 移除氢、标准化分子、生成canonical SMILES
    mol = Chem.RemoveHs(mol)
    return MolToSmiles(mol, canonical=True, isomericSmiles=False)

# 假设从CSV读取一行
raw_smiles = "C[C@@H](O)c1ccccc1"
std_smi = standardize_smiles(raw_smiles)
print(std_smi)  # 输出:CC(O)c1ccccc1

上面的代码我用了很多次。注意 isomericSmiles=False 会把手性信息丢掉——如果你需要保留立体化学,改成 True。具体要不要丢,取决于你后期的建模需求。我一般在整合多批次时先统一走无手性版本,等需要立体异构体时再单独标记。

曾经踩过的坑:有一次跑完标准化后,发现两个批次的化合物数量加起来比预期少了15%。一查,原来其中一个批次使用“InChI”列而不是“SMILES”列,我漏掉了。务必在读取CSV前打印所有列名,或者写个函数自动识别。

格式这东西,你越早统一,后面越省心。我见过团队因为懒得标准化,最后不得不写一个「格式适配器」来对接五个不同来源的数据库——那代码量,够写半篇论文了。