1. PDB 文件格式基础:搞懂分子结构的“通用语言”
做分子模拟或者结构生物学相关的开发,PDB 文件是绕不开的老朋友。说白了,它就是分子结构的“身份证”。你拿到一个 .pdb 文件,里面记录的就是一个个原子的坐标、属于哪个残基、在蛋白质链的什么位置等等。
我个人习惯把 PDB 文件看作一本“电话簿”。每条记录就是一行,告诉你谁在哪、干什么。不过这本电话簿有自己的规矩,了解清楚了,后面的批量验证才不会出错。
为什么会这样?因为 PDB 格式有严格的行记录类型。每行开头几个字母(比如 ATOM、HETATM、TER)就说明了这行数据的身份。
1.1 核心字段:看懂每一行在说什么
我挑几个最常见的记录类型讲。写代码处理PDB时,靠的就是这些标志性开头。
| 记录类型 | 首列标识 | 含义 | 备注 |
|---|---|---|---|
| ATOM | ATOM |
标准氨基酸或核酸的原子 | 最常见,构成蛋白质主链和侧链 |
| HETATM | HETATM |
非标准原子(配体、水、金属离子等) | 处理配体时这是主角 |
| TER | TER |
链的终止标记 | 告诉我一条链在这里结尾 |
| END | END |
文件结束 | 读到这行就收工 |
| MODEL | MODEL |
NMR 多模型结构的开始 | 常见于 NMR 解析的结构 |
我遇到过很多新手,上来就按行号硬解析。我的建议是——永远用前6个字符做类型判断。为什么?因为 PDB 文件里可能有注释行(REMARK)、连键信息(CONECT)等,直接按顺序读会跑偏。
核心原则:用记录类型首列做分支,不要依赖行号。
1.2 原子坐标与链的标识
ATOM 行里记录了最关键的信息。我直接给一个典型的示例:
ATOM 1 N ALA A 1 -0.525 1.362 0.000 1.00 0.00 N
这行里藏着什么?我们拆开看:
ATOM:记录类型1:原子序号,在文件内唯一N:原子名称(这里是主链氮)ALA:残基名称(丙氨酸)A:链标识(Chain ID),这里链叫“A”1:残基序号,在链内递增-0.525 1.362 0.000:X、Y、Z 坐标(单位埃)1.00 0.00:占据率和温度因子(B-factor)N:元素符号
嗯,这里要注意——链标识区分大小写。我遇到过不少新手栽在这里。某次合作,对方直接把 chain B 写成了 b,结果对接程序怎么都跑不通。你想想看,大写 A 和小写 a 在 PDB 规范中是两个不同的链。
1.3 残基与 Hetatm:别把水分子当成氨基酸
ATOM 行记录的是标准氨基酸或核酸的原子。而 HETATM 行则记录非标准的东西。这些包括:水分子、配体、金属离子、修饰过的氨基酸等等。
举个例子,水分子通常长这样:
HETATM 1234 O HOH A 201 2.345 1.234 5.678 1.00 20.00 O
残基名 HOH 就是水。处理的时候你要分清:
- 筛选配体时,只取 HETATM 但排除水(排除
HOH) - 分析晶体结构时,水的分布有时也是判断数据质量的一个指标
我的习惯:写代码分析配体时,先筛选 HETATM,再用残基名排除水、离子(如 NA、CL),剩下的基本就是配体小分子。
1.4 PDB 整体的结构层次
一个 PDB 文件可以很大,但它有固定的“从大到小”的包含关系。我把这张图画出来,你感受一下:
注意这个结构——文件包含模型,模型包含链,链包含残基,残基包含原子。在处理多链复合物时,要按这种层次组织数据。我曾经处理过一个抗体-抗原复合物,链 A 是抗体轻链,链 B 是抗体重链,链 C 是抗原。如果用链标识做分组,后面的相似性验证就好做多了。
1.5 命令示例:用 Python 快速解析 PDB 头信息
写代码时怎么判断一个 PDB 文件的结构?我习惯先扫描一遍,提取出链列表和每条链的残基范围。下面是一个简单示例:
def scan_pdb_header(pdb_path):
chains = {}
with open(pdb_path, 'r') as f:
for line in f:
if line.startswith(('ATOM ', 'HETATM')):
chain_id = line[21].strip()
res_name = line[17:20].strip()
res_num = int(line[22:26].strip())
if chain_id not in chains:
chains[chain_id] = {'residues': set(), 'res_range': [9999, -1]}
chains[chain_id]['residues'].add(res_name)
if res_num < chains[chain_id]['res_range'][0]:
chains[chain_id]['res_range'][0] = res_num
if res_num > chains[chain_id]['res_range'][1]:
chains[chain_id]['res_range'][1] = res_num
for ch, info in chains.items():
print(f"Chain {ch}: {info['res_range'][0]}-{info['res_range'][1]}, "
f"残基数: {len(info['residues'])}")
return chains
这个函数专门用于快速预览 PDB 里有哪些链、每条链的残基序号范围。我通常在跑批量验证前先跑一遍这个,确认数据没少链、残基没断层。
注意:PDB 格式里,残基序号在列 23-26(4 字符),链标识在列 22(1 字符)。列计数从 1 开始,这是老 Fortran 格式的遗留。写解析时务必注意起始列!
1.6 避坑指南:PDB 解析中常见的三个坑
- 行宽不固定?不可能。PDB 格式理论上每行固定 80 字符,但有些工具导出的文件可能多出空格或注释。别依赖、别偷懒——按列位置解析,不要按空格分割字符串。我当年用
line.split()接过一个文件,结果配体名里有空格,直接崩了。 - 残基序号可能重复。同一文件中,不同链的残基序号可能是一样的(比如链 A 的 1 号和链 B 的 1 号不是同一个)。按
链标识 + 残基序号做唯一键是稳妥做法。 - 水分子会干扰判断。统计残基种类时,记得把
HOH单独处理或过滤掉。不然配体分析时会混进几百个水分子。
1.7 小结
这一章我们搞清楚了 PDB 文件的核心骨架:ATOM 是主体,HETATM 是补充,链、残基、原子是逐层嵌套的关系。掌握了这些基础字段,就等于拿到了打开分子结构的钥匙。后面做批量相似性验证时,不管是比对原子坐标,还是对比残基序列一致性,都离不开这一章的内容。