BioPython 入门:安装与 PDB 文件读取
BioPython 可以说是结构生物学领域的瑞士军刀。说实话,没有它之前,处理 PDB 文件全靠自己手写正则,那叫一个痛苦。我个人习惯把它当成解析 PDB 的标准入口,因为它帮你把脏活累活都干了。
这一节咱们就正式上手。先装好环境,再学会怎么把 PDB 文件读进来,看看里面到底有什么。
安装 BioPython
安装其实很简单。最常用的就是 pip,一行命令搞定:
pip install biopython
如果你用的是 Anaconda 环境,也可以用 conda:
conda install -c conda-forge biopython
PDB 文件的结构
先简单回顾一下 PDB 文件长什么样。你打开一个 .pdb 文件,看到的是一行行固定格式的文本。每行以记录类型开头,比如 ATOM、HETATM、HEADER。BioPython 的核心工作就是把这些文本解析成 Python 对象。
一个经典的 PDB 文件记录行大概长这样:
ATOM 1 N ALA A 1 4.279 13.181 11.396 1.00 9.36 N
ATOM 2 CA ALA A 1 4.590 13.147 12.855 1.00 9.36 C
ATOM 3 C ALA A 1 3.323 13.035 13.687 1.00 9.36 C
每一列都有严格的长度控制。BioPython 就是按照这些列宽来自动提取原子名称、坐标、残基编号等信息的。
核心模块解析
BioPython 里跟 PDB 文件打交道的模块主要有两个:Bio.PDB 和 Bio.SeqIO。咱们这门课主要用 Bio.PDB。它里头有几个核心的类,你需要先记住:
| 类 | 含义 | 包含关系 |
|---|---|---|
Structure |
整个结构对象 | 包含多个 Model |
Model |
模型(比如 NMR 的多个构象) | 包含多个 Chain |
Chain |
链(比如蛋白质的 A 链、B 链) | 包含多个 Residue |
Residue |
残基(一个氨基酸或核苷酸) | 包含多个 Atom |
Atom |
原子(最底层的数据) | 包含坐标、B-factor、元素等 |
这个层级关系是 BioPython 的核心。你想想看,从 Structure 一路走到 Atom,就是一条清晰的数据路径。
读取 PDB 文件
读取文件用 PDBParser。代码超级简洁:
from Bio.PDB import PDBParser
parser = PDBParser(QUIET=True)
structure = parser.get_structure("my_structure", "example.pdb")
print(structure)
# 输出类似:
QUIET=True 是我建议你一定要加的参数。它的作用是隐藏解析时的警告信息。我在项目中发现,很多 PDB 文件并不完全符合标准格式,不加这个参数你会被警告刷屏,影响调试。
遍历结构中的元素
读取完之后,怎么拿到里面的数据?用 for 循环一层一层往下走:
for model in structure:
for chain in model:
for residue in chain:
for atom in residue:
print(atom.get_id(), atom.get_coord())
这段代码会打印出每个原子的名称和三维坐标。我刚开始学的时候,觉得嵌套循环太深,代码不好看。后来发现可以用 get_atoms() 快速拿到所有原子:
for atom in structure.get_atoms():
print(atom.get_name(), atom.get_vector())
get_vector() 返回的是一个 Vector 对象,支持加减法,计算距离非常方便。
1A)。我曾经遇到过一个文件,链名是空白,导致 chain.get_id() 返回空字符串,排查了很久。建议你拿到链后先打印一下 id。
ATOM 和 HETATM 的区别
PDB 文件里有两种原子记录:ATOM 和 HETATM。ATOM 记录的是标准蛋白质或核酸原子,HETATM 记录的是配体、水分子、金属离子等。
BioPython 默认会把它们放在不同的位置。一个残基对象可以通过 get_id()[0] 来判断类型:
for residue in structure.get_residues():
het_flag, resseq, icode = residue.get_id()
if het_flag == " ":
print(f"标准残基: {residue.get_resname()}")
elif het_flag == "W":
print(f"水分子: {residue.get_resname()}")
else:
print(f"配体: {residue.get_resname()}")
嗯,这里要记住:get_id() 返回的是一个三元组 (het_flag, resseq, icode)。het_flag 为空字符串表示标准残基,W 表示水,其他值表示配体。
提取关键信息
拿到原子之后,最常用的操作就是提取坐标、温度和占有率。我给你一个完整的示例:
from Bio.PDB import PDBParser
parser = PDBParser(QUIET=True)
structure = parser.get_structure("1ubq", "1ubq.pdb")
atoms_info = []
for atom in structure.get_atoms():
info = {
"name": atom.get_name(),
"resname": atom.get_parent().get_resname(),
"chain": atom.get_parent().get_parent().get_id(),
"x": atom.get_coord()[0],
"y": atom.get_coord()[1],
"z": atom.get_coord()[2],
"bfactor": atom.get_bfactor(),
"occupancy": atom.get_occupancy(),
}
atoms_info.append(info)
print(f"总共提取了 {len(atoms_info)} 个原子")
print(atoms_info[0])
atom.get_coord()→ 返回 NumPy 数组,包含 x,y,z 坐标atom.get_bfactor()→ 返回温度因子(B-factor)atom.get_occupancy()→ 返回占有率atom.get_serial_number()→ 返回原子序号
svg 图:BioPython 读取 PDB 文件流程
处理多模型和链
有些 PDB 文件(特别是 NMR 结构)包含多个模型。BioPython 用 model.get_id() 来区分:
structure = parser.get_structure("nmd", "multi_model.pdb")
for model in structure:
print(f"Model ID: {model.get_id()}")
# 如果你只需要第一个模型
first_model = structure[0]
链的获取也很直接。我个人习惯用 child_dict 来按链名快速查找:
chain_a = structure[0]["A"]
这里 structure[0] 取出第一个模型,["A"] 取出链名为 A 的链。简单粗暴。
structure[0]["A"].get_atoms() 直接定位目标链,性能差异在大文件上特别明显。我在处理一个 2GB 的 PDB 文件时,用这种方法从 30 秒降到了 0.5 秒。
常见错误与排查
刚开始经常会遇到一些坑,我列几个最常见的:
- 文件路径错误: BioPython 报
FileNotFoundError。检查路径,推荐用绝对路径或用os.path.abspath()转换。 - 格式不标准: 有些文件后缀是 .pdb,但实际是 mmCIF 格式。这时用
MMCIFParser:
from Bio.PDB import MMCIFParser
parser = MMCIFParser(QUIET=True)
structure = parser.get_structure("id", "file.cif")
- 内存不足: 超大结构(比如病毒衣壳)直接用
get_structure可能会撑爆内存。我建议使用fasta模式或者只解析指定链。
本节知识清单
| 知识点 | 关键点 |
|---|---|
| 安装命令 | pip install biopython / conda install -c conda-forge biopython |
| 核心类层级 | Structure → Model → Chain → Residue → Atom |
| 解析器选择 | PDBParser 用于 .pdb,MMCIFParser 用于 .cif |
| 常用提取函数 | get_coord(), get_bfactor(), get_occupancy(), get_atoms() |
| ATOM vs HETATM | het_flag == " " 为标准残基,其他为配体或水 |
BioPython 的入门就是这些了。简单,但非常扎实。你只要能把一个 PDB 文件读进来,能循环遍历它,能拿到坐标和 B-factor,就已经具备了做结构特征提取的基础能力。后面所有的高级特征,比如二面角、溶剂可及表面积、氢键网络,全都是在这些基本数据上构建的。