4. RMSD 计算原理:原子对匹配与最小二乘对齐
聊完了 RMSD 到底是什么,咱们得动真格的了——这东西到底怎么算出来的?
很多教程直接扔给你一个公式,但我发现这样学完,自己写代码的时候照样懵。我刚开始做结构比对的时候,就踩过这个坑:拿着两个 PDB 文件,直接套欧氏距离公式,出来的数字大得离谱,完全没法用。
后来才明白,计算 RMSD 之前,有两步预处理是绕不开的:原子对匹配和最小二乘对齐。缺了哪一步,算出来的都不对。
4.1 原子对匹配:先得知道谁跟谁比
说白了,RMSD 不是随便拿两个原子就算的。你得先告诉程序:结构 A 里的第 i 个原子,对应结构 B 里的第 j 个原子。这个对应关系,就是原子对匹配。
匹配思路有两种,我分别说说。
4.1.1 顺序同名匹配
这是最常用、也最直观的方法。两个蛋白序列比对好之后,按照残基编号一一对应。比如A链的Glu15对B链的Glu15,只算主链的N、CA、C、O这四个原子。
我在处理同源结构或突变体的时候,几乎都用这个方式。简单,可靠。
4.1.2 顺序无关匹配
但有些情况不能按编号来。比如结构域发生了重排,或者你比较的是两个只有功能相似但序列不相同的蛋白。这时候需要靠几何哈希或者图匹配算法,先找出空间位置接近的原子对,再去做比对。
这种计算量会大不少。我建议,除非你有明确的理由(比如做 fold-switching 研究),否则先用顺序匹配。
顺序相同 → 顺序同名匹配
结构域重排 / 序列差异大 → 顺序无关匹配(几何哈希)
4.2 最小二乘对齐:把两个结构叠到一起
匹配完成,接下来要解决一个很实际的问题:两个结构在空间里是随意摆放的,不可能直接算距离。你得先把它们“叠”在一起。
这个叠的过程,数学上叫最小二乘对齐。目标是找到一个旋转矩阵 R 和一个平移向量 t,让两个结构对应原子之间的平方距离之和最小。
公式表达就是:
min ∑ || R * A_i + t - B_i ||²
其中 A_i 是结构A的第i个原子坐标
B_i 是结构B的第i个原子坐标
R 是3×3旋转矩阵
t 是3×1平移向量
这个问题有解析解,最经典的算法叫 Kabsch 算法。我自己在项目里用过很多次,流程其实就四步。
4.2.1 Kabsch 算法流程
- 计算质心:分别算结构A和结构B所有对应原子的平均坐标。
- 去质心:每个原子的坐标减去所属结构的质心,得到新坐标A'和B'。
- 构造协方差矩阵:H = A'^T * B'
- SVD分解:H = U * Σ * V^T。旋转矩阵 R = V * U^T。
- 计算平移:t = 质心_B - R * 质心_A。
你看,原理不复杂。但实现的时候有细节:如果 det(V * U^T) 是负的,说明有反射变换,需要把V的最后一列取反,才能保证是一个纯旋转。
scipy.spatial.transform.Rotation.align_vectors 直接帮你干完了Kabsch的全部工作。但我建议你至少自己手写一次,不然遇到特殊case(比如点云退化)会很头疼。
4.3 SVG:RMSD 计算流程总览
为了让你更直观地理解整个流程,我画了一张图。从输入两个结构开始,到最终输出 RMSD 值,中间经过原子对匹配、最小二乘对齐和距离计算三个核心步骤。
4.4 对齐后的 RMSD 计算
对齐做完,事情就简单了。对每一对匹配好的原子,算欧氏距离,平方,求和,除以原子总数,再开方。
RMSD = sqrt( (1/N) * Σ || A_i_aligned - B_i ||² )
这里 A_i_aligned 是结构A经过旋转平移之后的新坐标。说白了,所有原子间的距离偏差都体现在这个单一数字里。
嗯,这里要注意一点:RMSD 对异常点非常敏感。如果你配对时混入了一两个严重错位的原子(比如 loop 区乱跑的残基),RMSD 会被迅速拉高。我一开初做药物筛选用 RMSD 做打分项,就吃了这个亏,一个离群原子让整个打分全乱了。后来加上离群点剔除的预处理,结果才稳下来。
• 原子对匹配是前提,匹配错误 → RMSD 毫无意义
• 最小二乘对齐必须去质心 + SVD,不能略过
• 最终 RMSD 的数值受离群点影响很大,建议考虑截断或鲁棒版本(如 RMSD_95)