如何用Python自动化实现含不同蛋白质的大量mmCIF文件的结构叠加、RMSD计算与筛选
如何用Python自动化实现含不同蛋白质的大量mmCIF文件的结构叠加、RMSD计算与筛选
嗨,看起来你现在卡在两个关键问题上:一个是代码参数传递的低级错误,另一个是不同蛋白质结构原子不匹配的核心难题。我来一步步帮你搞定:
首先,先修复当前的TypeError错误
你现在的报错完全是参数传错了:
- 你调用
calculate_rmsd(mmcif_list, mmcif_ref, mmcif_comp)时,第一个参数传的是文件名列表mmcif_list,但函数定义里第一个参数需要的是文件夹路径mmcif_dir(字符串类型) - 而且
mmcif_comp是多个文件的列表,但你的函数里把它当成单个文件来解析,这肯定会炸锅
先把这个基础问题解决,我们先把函数改成能处理单个待比较文件,再用循环遍历所有待比较文件:
import os from Bio.PDB import MMCIFParser, Selection, Superimposer from Bio import AlignIO from Bio.PDB.Polypeptide import PPBuilder # 初始化路径 cur_dir = os.getcwd() protein_name = "你的蛋白家族名称" # 记得替换成实际名称 mmcif_dir = os.path.join(cur_dir, protein_name, "input", "cif_files") output_dir = os.path.join(cur_dir, protein_name, "prep") os.makedirs(output_dir, exist_ok=True) # 确保输出文件夹存在 # 获取所有cif文件列表 mmcif_list = [f for f in os.listdir(mmcif_dir) if f.endswith('.cif')] mmcif_ref = mmcif_list[0] mmcif_comp_list = mmcif_list[1:] # 待比较的文件列表 print(f"参考文件: {mmcif_ref}") print(f"待比较文件数量: {len(mmcif_comp_list)}")
核心问题:不同蛋白质的原子匹配问题
你提到的“不同原子无法计算RMSD”是关键——BIO.PDB的Superimposer要求两个结构的原子列表完全一一对应(数量相同,顺序对应同源残基)。所以我们需要先做序列比对,找到两个结构的同源残基,再提取对应的骨架原子(N/CA/C)来计算。
下面是整合了序列比对+RMSD计算的完整函数,以及筛选逻辑:
def get_structure_sequence(structure): """从结构对象中提取氨基酸序列""" ppb = PPBuilder() sequences = [] for pp in ppb.build_peptides(structure): sequences.append(str(pp.get_sequence())) # 假设我们取第一个链的序列(如果有多个链,你可能需要调整逻辑) return sequences[0] def calculate_rmsd_between_structures(ref_structure, comp_structure): """计算两个结构之间的RMSD(先做序列比对匹配残基)""" # 提取两个结构的序列 ref_seq = get_structure_sequence(ref_structure) comp_seq = get_structure_sequence(comp_structure) # 做全局序列比对(用Bio.Align的PairwiseAligner) from Bio.Align import PairwiseAligner aligner = PairwiseAligner() aligner.mode = 'global' aligner.match_score = 2 aligner.mismatch_score = -1 aligner.open_gap_score = -2 aligner.extend_gap_score = -1 # 得到最优比对结果 alignments = aligner.align(ref_seq, comp_seq) best_alignment = alignments[0] ref_aln, comp_aln = best_alignment # 匹配同源残基:找到比对中没有gap的位置 ref_residues = [] comp_residues = [] ref_idx = 0 comp_idx = 0 for r, c in zip(ref_aln, comp_aln): if r != '-' and c != '-': # 获取对应的残基对象(这里假设取第一个模型的A链,根据实际情况改) ref_chain = ref_structure[0]['A'] comp_chain = comp_structure[0]['A'] # 注意:残基的ID格式通常是(空格, 残基号, 空格),需正确索引 ref_res = ref_chain[(' ', ref_idx+1, ' ')] comp_res = comp_chain[(' ', comp_idx+1, ' ')] ref_residues.append(ref_res) comp_residues.append(comp_res) if r != '-': ref_idx += 1 if c != '-': comp_idx += 1 # 提取对应残基的骨架原子(N/CA/C) ref_atoms = [] comp_atoms = [] for ref_res, comp_res in zip(ref_residues, comp_residues): for atom_name in ['N', 'CA', 'C']: if atom_name in ref_res and atom_name in comp_res: ref_atoms.append(ref_res[atom_name]) comp_atoms.append(comp_res[atom_name]) # 做结构叠加并计算RMSD super_imposer = Superimposer() super_imposer.set_atoms(ref_atoms, comp_atoms) super_imposer.apply(comp_structure.get_atoms()) return super_imposer.rms # 先解析参考结构 parser = MMCIFParser(QUIET=True) # QUIET=True关闭解析时的冗余警告 ref_structure = parser.get_structure("reference", os.path.join(mmcif_dir, mmcif_ref)) # 设置RMSD阈值,比如只保留RMSD小于2.0的结构 rmsd_threshold = 2.0 # 遍历所有待比较文件,计算RMSD并筛选 for comp_file in mmcif_comp_list: try: comp_structure = parser.get_structure("comparison", os.path.join(mmcif_dir, comp_file)) rmsd = calculate_rmsd_between_structures(ref_structure, comp_structure) print(f"文件 {comp_file} 与参考结构的RMSD: {rmsd:.2f} Å") # 如果符合阈值,保存到输出文件夹 if rmsd <= rmsd_threshold: import shutil shutil.copy(os.path.join(mmcif_dir, comp_file), os.path.join(output_dir, comp_file)) print(f"已保存符合条件的文件: {comp_file}") except Exception as e: print(f"处理文件 {comp_file} 时出错: {str(e)}")
一些需要注意的细节
- 链ID和模型的选择:上面的代码假设所有结构都是单模型、单链(链ID为'A'),如果你的文件有多模型或多链,需要调整
ref_structure[0]['A']这部分的逻辑,比如遍历所有链或者指定目标链。 - 残基编号的处理:有些mmCIF文件的残基ID可能包含插入码(比如
( ' ', 100, 'A' )),如果遇到这种情况,你需要在提取残基时做更灵活的匹配。 - 序列比对的参数:你可以根据你的蛋白家族调整
PairwiseAligner的得分参数,比如gap罚分、匹配得分等,让比对结果更准确。 - 异常处理:加入了
try-except块,避免某个文件解析失败导致整个程序崩溃。
备注:内容来源于stack exchange,提问作者y.a




