PDB 与 SDF 文件格式概述
做计算化学或结构生物学的人,天天都得跟这两种文件打交道。PDB 和 SDF,说白了就是装分子信息的“容器”。但哪个容器装什么、怎么装,坑不少。我最早接触 PDB 文件时,被它那套历史遗留格式折腾得不轻。今天咱们就先把这俩格式的底牌翻出来看看。
PDB 格式:一个老牌选手的前世今生
PDB 全称叫 Protein Data Bank,它既是一个数据库,也是一种文件格式。1971 年诞生,那时 ASCII 编码还是主流。说白了,它就是个固定宽度的文本文件,每一行 80 个字符,连列宽都是死规矩。
为什么会这样?因为当年打孔卡片就是 80 列。嗯,这格式一直用到现在。
核心原则:PDB 格式以原子为单位,每个原子占用固定列位。列错了,读出来的坐标就对不上。
文件里最常见的记录类型有这些:
| 记录类型 | 说明 |
|---|---|
| HEADER | 文件头部,包含分子类型和日期 |
| ATOM | 标准氨基酸原子、水分子坐标 |
| HETATM | 非标准残基、配体、修饰原子 |
| CONECT | 明确的原子连接关系 |
| END | 文件结束标志 |
一个典型的 ATOM 记录长这样:
ATOM 32 CA ALA A 5 11.261 6.702 10.318 1.00 12.93 C
每个字符范围都有严格定义。比如原子名“CA”,必须从第 13 列开始。如果写歪了一个空格,Parser 就会读错。我之前在项目里遇到过一批第三方转换的 PDB 文件,所有坐标列都偏移了一列。调 bug 调了一整天,最后发现是序列号里多了一个空格。从那以后,我拿到 PDB 文件第一件事就是做格式校验。
PDB 的结构数据:不仅仅是坐标
PDB 文件不止存 xyz 坐标。它还记录了:
- 残基序列:整条链的氨基酸顺序
- 二级结构:alpha 螺旋、beta 折叠的指派
- 晶体学数据:空间群、分辨率、R 因子
- 注释信息:配体结合位点、突变信息
解析时有个难点:多构象和多链。同一个残基可能存了 2 套坐标,用 A/B 标注。你想想看,如果无脑写代码,把所有原子都当成独立的,那分子拓扑就全乱了。
我的习惯:用 biopython 的 PDBParser 做解析。够稳,对多构象处理也好。
from Bio.PDB import PDBParser
parser = PDBParser(QUIET=True) # QUIET=True 关掉冗余警告
structure = parser.get_structure("example", "1ubq.pdb")
for model in structure:
for chain in model:
for residue in chain:
for atom in residue:
print(atom.get_id(), atom.get_vector())
SDF 格式:小分子的“万能工”
SDF,全称 Structure-Data File。它比 PDB 年轻一点,是 MDL 在 1980 年代推出来的。设计目标很明确——存小分子结构 + 任意自定义属性。
格式分三段:
- 头块:分子名,程序信息
- 原子块 + 键块:坐标、原子类型、键连接
- 数据块:键值对形式的属性,以 > 开头
一个典型的 SDF 结构如下:
mol_123
ChemOffice 20.0
20 22 0 0 0 0 0 0 0 0
1.2345 2.3456 3.4567 C 0 0 0 0 0 0
2.3456 3.4567 4.5678 N 0 0 0 0 0 0
...
1 2 1 0 0 0
2 3 2 0 0 0
...
M END
> <LogP>
2.34
> <MW>
180.16
$$$$
看到那个 $$$$ 了吗?那是记录分隔符。一个 SDF 文件可以包含几万个小分子,每个用 $$$$ 隔开。做虚拟筛选时,经常一个文件就上百 MB。
我曾经踩过的坑:某些 SDF 文件里坐标用的整数,是缩放过的。读的时候要检查 V2000 还是 V3000 格式。V3000 用了 M 后缀,语法完全不同。
各自的长处与短板
两个格式各有侧重。我列个表格对比一下:
| 维度 | PDB | SDF |
|---|---|---|
| 适用范围 | 蛋白质、核酸、大分子复合物 | 小分子、配体、有机化合物 |
| 结构精度 | 实验测定,0.1 Å 级 | 计算模型,精度依情况而定 |
| 属性扩展 | 差,只能通过 REMARK 行自己加 | 好,数据块支持任意键值 |
| 多分子支持 | 通常一文件一个结构 | 天然支持多个记录 |
| 标准解析 | 规则 | 偶有歧义,尤其是 V3000 |
PDB 的优势在于标准统一,全世界共用。但缺点是扩展性差。想加个自定义属性?只能写在 REMARK 行里,随便写,谁写谁读,没人管格式。
SDF 的优势恰恰是灵活。LogP、MW、SMILES、活性数据,全可以塞进数据块。但问题也出在这——一家一个写法,有的字段名大小写不统一,有的值是字符串有的又是浮点。解析时得很小心。
我个人建议,做蛋白-配体对接时,蛋白用 PDB,配体用 SDF。但配体坐标要转成 PDB 格式才能一起输入到 Docking 软件里。这就是预处理的工作了。你想想看,如果配体 SDF 里的原子类型写的是“C.ar”(芳香碳),某些对接程序不认识它,直接当成未知原子类型报错。
# 快速检查 SDF 中的原子类型
from rdkit import Chem
suppl = Chem.SDMolSupplier("ligands.sdf")
for mol in suppl:
if mol is None:
continue
for atom in mol.GetAtoms():
print(atom.GetSymbol(), atom.GetIsAromatic())
一句话总结:PDB 是“老派但靠谱”的大分子容器,SDF 是“灵活略粗糙”的小分子容器。预处理的关键,就是在这两个格式之间搭好桥。