第4章:药物分子数据预处理概述:常见格式与清洗目标
做药物分子数据预处理,第一关永远是格式。SDF、SMILES、PDB——这三个家伙几乎占据了所有分子数据交换的场景。我记得刚入行时,接手一个虚拟筛选项目,上游给了几百个SDF文件,下游对接的模型死活只能读SMILES字符串。当时花了两天写格式转换脚本,结果发现字段对不齐、原子计数少了、立体化学信息丢失……从那以后,我再也不敢轻视格式预处理这一步了。
这章我们就聊透彻:这三种格式到底长什么样?它们各自擅长什么?最常踩的坑在哪?以及,我们最终要洗出什么样的数据。
1. SDF:结构数据文件
SDF(Structure Data File)可以说是化学信息学最通用的格式之一了。它来自MDL公司的CTfile规范,一个文件可以存一个或多个分子。结构片段(原子坐标、键连接)和数据字段(分子量、LogP、CAS号等)打包在一起。
我个人习惯在处理公共数据库(比如ChEMBL、PubChem)时优先看SDF,因为它是“结构+属性”的完整快照。你想想看,一个SDF文件长这样:
O1
-MDL-0931160300
9 9 0 0 0 0 0 0 0 0999 V2000
1.2345 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
2.3456 1.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3.4567 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
0.1234 -0.7000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0
2 3 1 0
3 1 1 0
1 4 1 0
3 4 1 0
M END
>
CHEMBL12345
>
180.16
$$$$
每个分子以$$$$结束,atom block和bond block的数据列含义固定。这里有个坑:
$$$$分隔符或属性字段名不规范。结果Snakemake管道读入后直接报错,排查了一整天才发现是最后一条记录没闭合。所以写SDF解析器时,一定要检查记录数目和属性块完整性。
SDF的主要用途:
- 存储小分子的完整2D/3D构象
- 携带任意数目的用户自定义字段
- 作为数据库导出/导入的标准格式
2. SMILES:一行搞定分子结构
SMILES(Simplified Molecular Input Line Entry System)是另一种极端——用一行ASCII字符串表示整个分子。它的核心是深度优先遍历连接图,再用分支和环标记。
举个例子,阿司匹林的SMILES是 CC(=O)Oc1ccccc1C(=O)O。你看,原子、双键、环编号、括号里的支链都在一行里。好处是极其轻量,适合网络传输、数据库主键、模型输入。坏处呢?
我在项目中遇到过很多“非标准SMILES”。比如:
- 不规范环编号(不同工具对环的表示顺序不一样)
- 缺少氢原子(隐式氢 vs 显式氢混用)
- 立体化学信息模糊(@和@@符号位置搞反)
所以预处理时,我建议统一规范化工具,比如用Open Babel或RDKit的MolFromSmiles再MolToSmiles,这样能保证输出规范的Canonical SMILES。下面是一段Python演示:
from rdkit import Chem
smiles = "c1ccccc1C(=O)O" # 不规范:苯环用低编号,但可接受
mol = Chem.MolFromSmiles(smiles)
canon = Chem.MolToSmiles(mol) # 输出 O=C(O)c1ccccc1
print(canon)
3. PDB:蛋白质的坐标语言
PDB(Protein Data Bank)格式是生物大分子的标准。一个PDB文件记录每个原子的x、y、z坐标、残基名、链标识、温度因子等。小分子配体通常也会被放在HETATM记录区。
但处理PDB时最让人头疼的是数据不一致性:
- 同一个蛋白可能有多个变体,原子编号不相同
- 缺失残基、侧链断开
- 溶剂分子、配体、离子混在一起
- 分辨率低,导致坐标精度不足
我曾经处理一个对接项目,下游的AutoDock工具要求配体PDB文件中不能有氢原子,而受体需要极氢。结果上游给的文件里全混杂了,装进Snakemake后死活跑不过。后来我专门写了一个rule,用reduce工具加氢,再用obabel删掉非必要原子。
PDB文件中一个典型片段:
ATOM 22 CG ASP A 3 -2.316 1.695 2.140 1.00 0.00 C
ATOM 23 OD1 ASP A 3 -1.318 1.348 2.849 1.00 0.00 O
ATOM 24 OD2 ASP A 3 -3.511 1.390 2.252 1.00 0.00 O
HETATM 25 C1 LIG L 1 3.424 -0.877 0.556 1.00 0.00 C
格式对比一览
| 属性 | SDF | SMILES | PDB |
|---|---|---|---|
| 表现方式 | 块结构 + 坐标 + 字段 | 一行字符串 | 固定宽度文本 + 坐标 |
| 适用范围 | 小分子(多记录) | 小分子(单行) | 生物大分子、配体复合物 |
| 立体化学 | 支持(parity字段) | 支持(@/@@) | 不直接,需残基命名推断 |
| 数据冗余 | 较大(含坐标+字段) | 极小 | 较大(含晶胞等元信息) |
| 主要清洗问题 | 字段缺失、分隔符错误、坐标异常 | 非标准环表示、隐式氢歧义、立体化学颠倒 | 原子编号不一致、缺失原子、水分子干扰、链定位 |
| 工具推荐 | Open Babel, RDKit, obabel | RDKit, Open Babel | PyMOL, Reduce, Open Babel |
清洗目标:我们要达到什么效果?
说来说去,预处理无非四个核心目标:
- 标准化 – 把所有输入格式统一成一种内部表示(比如SDF或Canonical SMILES),去掉没必要的信息(比如3D坐标转2D或统一原子类型)。
- 去重 – 同一个分子可能在不同数据库里出现了多次,SMILES表示可能不一样。我习惯先用InChI或Canonical SMILES去重,再根据结构相似性合并。
- 过滤异常 – 那些原子数<2的、分子量超千的、含有非标准元素的……统统该筛掉。记得有一次管道跑到一半,打印出来一个“分子”只有两个氢原子,加氢后变成H2,完全没意义。还好snakemake的日志提醒了我。
- 补齐缺失信息 – 比如从SMILES到3D坐标、加氢、分配原子类型。这些操作往往依赖RDKit或Open Babel,且应当做成可复用的rule。
下面是整个预处理的逻辑流程,我经常在纸上画出来再写Snakemake规则:
说白了,预处理就是“把脏数据擦干净、格式统一、规则明确”的过程。你想想看,如果输入是一团乱麻,后面再牛的模型也白搭。Snakemake的优势就在于你可以把上面的流程拆成一个个rule,每次只处理一个步骤,中间产物的文件通过通配符传递,可追踪、可复用。