1. 认识PDB文件格式:一个结构生物学家的老朋友
说起PDB格式,它绝对是结构生物学里最“古老”的数据格式之一。我本科那会儿第一次打开一个PDB文件,满屏的数字和字母看得我头皮发麻——这玩意儿怎么读?后来做了几年结构数据清洗,才发现这位“老朋友”虽然年纪大了点,但真的很有内涵。
PDB格式是Protein Data Bank的缩写,诞生于上世纪70年代。说白了,它就是一套描述生物大分子三维结构的“标准语法”。我们做数据清洗,第一步就得读懂这套语法。
1.1 一个真实的PDB文件长什么样
先别急着看密密麻麻的规范文档。咱们直接打开一个真实的PDB文件看看。我习惯用胰岛素的一段记录当例子,它特别能说明问题:
HEADER HORMONE 01-JAN-98 1INS
ATOM 1 N ALA A 1 5.123 3.456 2.789 1.00 16.00 N
ATOM 2 CA ALA A 1 6.234 4.567 3.890 1.00 17.00 C
ATOM 3 C ALA A 1 7.345 5.678 4.901 1.00 18.00 C
ATOM 4 O ALA A 1 8.456 6.789 5.012 1.00 19.00 O
ATOM 5 CB ALA A 1 5.678 4.890 2.345 1.00 15.00 C
TER
HETATM 10 O HOH A 101 9.012 7.890 6.123 1.00 20.00 O
END
嗯,是不是看着有点眼花?我来拆开讲,你马上就能看懂。
1.2 原子记录格式:别被80列吓到
早期的PDB格式规定每行必须严格80列。为什么?因为那时候用的还是打孔纸带和宽行打印机。现在虽然不强制了,但绝大多数PDB文件还沿用这个传统。我个人觉得,这反而让格式更整齐,解析起来也简单。
原子记录主要分两种:ATOM和HETATM。ATOM记录标准氨基酸/核酸的原子,HETATM记录配体、水分子等“非标”东西。它们的字段位置完全一样:
| 列位置 | 字段名 | 说明 | 示例 |
|---|---|---|---|
| 1-6 | 记录类型 | ATOM 或 HETATM | ATOM |
| 7-11 | 原子编号 | 整数,建议连续 | 5 |
| 13-16 | 原子名称 | 左侧留空格,右侧对齐 | CB |
| 17-17 | 备选位置 | 有空位异构时用A/B/C | |
| 18-20 | 残基名称 | 三字母代码 | ALA |
| 22-22 | 链标识 | 单字母A-Z | A |
| 23-26 | 残基编号 | 整数,可用负值 | 1 |
| 27-27 | 插入码 | 如晶体制备时插入的残基 | |
| 31-38 | X坐标 | 浮点数,单位埃 | 5.678 |
| 39-46 | Y坐标 | 浮点数,单位埃 | 4.890 |
| 47-54 | Z坐标 | 浮点数,单位埃 | 2.345 |
| 55-60 | 占据率 | 0.00-1.00 | 1.00 |
| 61-66 | 温度因子 | 也叫B因子,单位平方埃 | 15.00 |
| 77-78 | 元素符号 | 靠右对齐 | C |
核心提示:解析PDB时我推荐用固定列宽截取,而不是用空格split。因为原子名称和残基名称可能连在一起。用split碰到"CA"和" A"的区别,你会头大的。
1.3 坐标数据:从XYZ到实际应用
坐标数据是PDB的核心,三个浮点数定义了原子在三维空间的位置。单位都是埃(Å),1Å = 0.1纳米。做数据处理时,我见过最多的问题就是单位搞混了——有人把坐标当纳米处理,计算出来的键长全是错的。
占据率这个字段,新手容易忽略。它表示这个原子在晶体里的“出现概率”。理想情况下是1.00,但侧链柔性大的残基,或者配体结合不明确的地方,可能会出现0.50甚至更低。我个人习惯,做能量计算前会把占据率低于0.50的原子去掉,否则结果偏差很大。
温度因子(也叫B因子)更有意思。它反映的是原子的运动幅度。B因子越大,原子越“抖”。我曾经帮一个课题组清理数据,他们发现某个活性位点的配体B因子特别高——后来证明那个配体根本没结合好,是晶体打包时硬塞进去的。
小技巧:做结构比对前,先看看B因子。残基的B因子如果超过80,它的坐标基本不可信。这是我从无数失败的叠加里总结出来的。
1.4 注解字段:藏在文件里的“剧情简介”
PDB文件不只是原子坐标。文件头部的HEADER、TITLE、COMPND、SOURCE这些注解字段,记录了实验信息、分子来源、功能描述。做数据清洗时,千万别忽略它们。
举个真实的例子。有一次我批量处理冗余的PDB结构,发现两条记录一个标的是“人胰岛素”,另一个标的是“猪胰岛素”,但坐标对得严丝合缝。查了SOURCE记录才知道:后者虽然标的猪,但表达系统是人源细胞,测出来构象一模一样。如果光对坐标,我会直接删掉一个,就漏掉这条重要信息了。
几个常用的注解字段:
- HEADER:分子类型,比如HORMONE、TRANSPORT PROTEIN
- TITLE:实验的简短描述,常包含突变信息和配体信息
- COMPND:分子名称,包括链的命名
- SOURCE:表达系统,对理解翻译后修饰很重要
- KEYWDS:关键词,方便检索和分类
- REMARK 2:分辨率信息,这是质量评价的第一道门槛
1.5 PDB格式的两大“坑”
讲了这么多好的,也得说说坑。我花了至少两个月才彻底搞明白这两个问题:
避坑指南1:链标识不是唯一的
不同的PDB文件,同样的链可能叫A,也可能叫B,还可能同一个链在不同模型中用不同的字母。做跨文件比对时,绝对不能只靠链字母对应。我建议自己重新编号,按连续残基顺序标链。
避坑指南2:原子名称的对齐规则
标准氨基酸的原子名称放在13-16列,是“右侧对齐左侧留空”的。比如Cα写为" CA",不是"CA "。而水分子氧原子写为" O "。用split(' ')拆分时,空字符串能把你逼疯。我统一用固定列宽截取,再也不纠结。
1.6 知识结构总览
在你开始实战解析前,先看看PDB格式的整体骨架。下面这张图总结了我们刚才讲的核心内容:
1.7 实战准备:用Python读一行PDB
理论讲完,还是得动手。这是我写的第一版PDB解析函数的简化版,留给你当模板:
def parse_atom_line(line):
"""
解析单行ATOM/HETATM记录
返回字典,失败返回None
"""
# 检查记录类型
rec_type = line[0:6].strip()
if rec_type not in ("ATOM", "HETATM"):
return None
record = {
"type": rec_type,
"serial": int(line[6:11].strip()),
"name": line[12:16].strip(),
"alt_loc": line[16:17].strip(),
"res_name": line[17:20].strip(),
"chain": line[21:22].strip(),
"res_seq": int(line[22:26].strip()),
"i_code": line[26:27].strip(),
"x": float(line[30:38].strip()),
"y": float(line[38:46].strip()),
"z": float(line[46:54].strip()),
"occupancy": float(line[54:60].strip()),
"b_factor": float(line[60:66].strip()),
"element": line[76:78].strip()
}
return record
注意,我这里用的全是固定列宽截取。你可以自己试试,如果换成line.split(),原子名为" CA"时split的结果会多一个空串,这个bug能让你debug到怀疑人生。
好了,PDB文件的基本骨架你已经摸清了。下一阶段我们会深入到格式变种和异常处理——相信我,PDB文件里的“妖怪”比你想象的多。