1. PDB 文件格式基础:历史、用途与结构解析

PDB 文件,全称 Protein Data Bank 文件格式。说白了,它就是生物大分子世界的“通用语言”。

你手里有一份晶体结构数据,想发给合作者看看?用 PDB。你想在 PyMOL 里可视化一个蛋白质?先加载 PDB。你想跑个分子动力学模拟?输入文件多半也是 PDB。我在项目中遇到过不下百次这样的场景:不同实验室、不同软件,全靠这个格式来沟通。

1.1 一个“意外”诞生的标准

PDB 格式的历史,其实挺有意思。1971年,布鲁克海文国家实验室的几位结构生物学家,为了解决数据共享的难题,建立了一个公共数据库。当时他们没想太多,就设计了一套简单的固定列宽格式来记录原子坐标。

嗯,你没听错——固定列宽。每一行从第几个字符到第几个字符代表什么,都是写死的。这在今天的 JSON、YAML 满天飞的环境下,显得有点“复古”。

我个人习惯把 PDB 格式看作“打了格的作文纸”。每个字段的位置是固定的,解析器就按位置“抠”数据。这在 70 年代很合理,因为那时磁盘空间和金贵,固定格式解析起来最快。

数据库的访问量增长飞快。到了 90 年代,PDB 格式已经成了结构生物学的事实标准。我记得当年读文献时,几乎所有结构数据的补充材料里都附带一个 .pdb 文件。即便是现在,新格式 mmCIF 已经主流化,PDB 格式依然因其简洁、易读、解析成本低而广泛存在。

1.2 PDB 文件到底在记录什么?

一份标准的 PDB 文件,包含以下几个核心信息块:

信息类别 记录类型(Record Type) 内容说明
文件头部 HEADER / TITLE / COMPND 分子名称、分类、来源、发表文献等元数据
结晶/实验信息 CRYST1 / REMARK 晶胞参数、空间群、数据收集与精修方法
序列与链信息 SEQRES / DBREF 氨基酸或核苷酸序列、链标识符、数据库交叉引用
原子坐标 ATOM / HETATM 每个原子的名称、残基类型、直角坐标 (x, y, z)、温度因子 (B值) 和占有率
化学键与连接 CONECT / LINK / SSBOND 非标准化学键、二硫键、配体连接
注释与结束 REMARK / END 实验细节、功能注释;文件结束标记

其中最为核心的,就是 ATOM 和 HETATM 记录。你后期做的所有特征提取——从计算溶剂可及性表面积到分析残基接触网络——都离不开这些原子坐标。

1.3 ATOM 记录:你手把手读懂一行坐标

我们来看一个真实的 ATOM 行:

ATOM      1  N   ALA A   1      19.296  13.249  28.553  1.00  42.18           N

别被这一串吓到。我们用“固定列宽”的思维拆解一下:

  • 列 1-6: "ATOM " — 记录类型,固定 6 个字符。
  • 列 7-11: " 1" — 原子序号,右对齐。
  • 列 13-16: " N " — 原子名称。这里的空格位置很有讲究,标准原子名在列 13-14,右侧可能有空格。
  • 列 17: " " — 备用位点指示符。如果是 'A' 或 'B',表示这个原子有交替构象。我曾经因为这个字段没处理好,导致有多个构象的结构计算出了很大偏差。避坑指南:解析时不要忽略这个字段。
  • 列 18-20: "ALA" — 残基名称,三字母缩写。
  • 列 22: "A" — 链标识符。如果结构只有一条链,通常是空格或 'A'。
  • 列 23-26: " 1" — 残基号。
  • 列 27: " " — 插入码。用于处理序列中插入的额外残基。
  • 列 31-38, 39-46, 47-54: 直角坐标 x, y, z,单位是 埃(Å)。
  • 列 55-60: " 1.00" — 占有率。通常为 1.0,表示该位置完全被这个原子占据。
  • 列 61-66: " 42.18" — 温度因子(B-factor)。值越高,代表这个原子在晶体中震动得越厉害,或者说它的位置越不确定。
  • 列 77-78: " N" — 元素符号。
给解析初学者的提示: 别用空格直接 split。 因为原子名称 " N " 和 " CA " 里的空格是字段内部数据。 你应该按照 PDB 格式规范,用字符串切片(substring)来硬解析。 我从踩过这个坑到现在,写 Python 解析器时一定用 line[12:16] 取原子名,而不是 line.split()。

1.4 一张图厘清 PDB 文件的核心结构

我把上面讲的内容,画成了一张结构图。你顺着箭头看,就能理解 PDB 文件的整体轮廓。

PDB 文件结构总览 文件头 (HEADER) 分子名称、分类、文献、来源 实验与注释 (REMARK / CRYST1) 结晶条件、精修参数、晶胞信息 序列与交叉索引 (SEQRES / DBREF) 氨基酸/核酸序列、UniProt ID 等 A T O M / H E T A T M 原子名称、坐标 (x,y,z)、链、残基 B-factor、占有率、元素符号 连接与修饰 (CONECT / SSBOND) 二硫键、配体-蛋白连接 元数据与结尾 (END) 晶胞对称、文件结束标记 核心原则:固定列宽 + 按行解析 每一行从固定的字符位置开始读取不同字段。解析器不需要“理解”内容,只需要“掐位置”就行。

1.5 现代工具怎么读 PDB?

在 Python 里,我们有多个选择。我个人最常用 Biopython,因为它的 PDB.PDBParser 模块封装了几乎所有解析细节。

给你看一个最基础的解析脚本——我建议初学的朋友先从这种写法开始,不要急着上复杂的数据结构:

from Bio.PDB import PDBParser

parser = PDBParser(QUIET=True)
structure = parser.get_structure("1ubq", "1ubq.pdb")

for model in structure:
    for chain in model:
        for residue in chain:
            for atom in residue:
                # 取出你需要的信息
                atom_name = atom.get_name()       # " N  ", " CA "
                coord = atom.get_vector()          # Numpy array [x, y, z]
                b_factor = atom.get_bfactor()      # 温度因子
                occupancy = atom.get_occupancy()   # 占有率
                element = atom.element              # 元素符号(自动推断)

                print(f"{residue.get_resname()} {residue.get_id()[1]} {atom_name}: {coord}")

解析原子要取什么?

你别把整行 ATOM 记录都存成字符串。你应该关注三项数据:坐标(几何位置)、B-factor(柔性/有序度)、残基身份(序列信息)。后面做特征工程,比如计算残基间距、分析活性口袋的柔性,全靠这三项。

如果不依赖 Biopython,自己手写一个解析器也很直接。关键是掌握固定列宽的偏移量:

def parse_atom_line(line):
    if line.startswith("ATOM") or line.startswith("HETATM"):
        serial = int(line[6:11].strip())
        name = line[12:16].strip()
        alt_loc = line[16]
        resname = line[17:20].strip()
        chain_id = line[21].strip() if line[21] != ' ' else ''
        resseq = int(line[22:26].strip())
        icode = line[26].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())
        bfactor = float(line[60:66].strip())
        element = line[76:78].strip()
        return {
            "serial": serial,
            "name": name,
            "resname": resname,
            "chain": chain_id,
            "resid": resseq,
            "x": x, "y": y, "z": z,
            "b_factor": bfactor,
            "occupancy": occupancy,
            "element": element
        }
一个我踩过的坑: 有些老式 PDB 文件里,在列 72-76 区域会有残基的电荷注释,比如 "2+" 或 "1-"。如果你解析时 float() 了对整个坐标字段,会直接报错。所以做通用解析器时,最好先强检查 len(line) >= 54。

OK,PDB 文件的过去、现在和它的“骨架”就讲到这儿。你手头如果有一个 .pdb 文件,建议现在就打开它,对照着上面的 ATOM 行拆解,看一遍就全明白了。