作者:Eric
创建时间:2026-04-16 11:06
这篇记什么
- 量化同一序列多肽(蛋白质)相似性,使用RMSD+Kabsch算法
- 进行Kabsch算法的推导及揭示其对应的数学原理
- 给出算法对应的python实现
主要内容
问题提出(刚体配准问题)
设有两组组成完全相同对应点(pdb文件中的ATOM行):
pi∈P,qi∈Q,i=1,2,…,N
在经过配准后
Pfit=PR+T
希望求旋转矩阵 R 和平移向量 T ,使得目标函数
R,Tmini=1∑N∥piR+T−qi∥2
达到最小,其中 R 满足
RTR=I
在蛋白质结构中,一般还需令 det(R)=1 来保证该蛋白质不存在镜面对称构象。
求解过程
-
消除平移向量 T
定义目标函数
F(R,T)=i=1∑N∥piR+T−qi∥2
对 T 求偏导,并令其为零:
∂T∂F=2i=1∑N(piR+T−qi)=0
因此
NT=i=1∑N(qi−piR)
从而
T=N1i=1∑Nqi−N1i=1∑NpiR
记两组点的质心分别为
pˉ=N1i=1∑Npiqˉ=N1i=1∑Nqi
则平移项可改写为
T=qˉ−pˉR
将 T 代入目标函数,得
F(R)=i=1∑N∥piR+qˉ−pˉR−qi∥2
整理后可得
F(R)=i=1∑N∥(pi−pˉ)R−(qi−qˉ)∥2
-
优化目标函数 F(R)
定义去中心化后的坐标
xi=pi−pˉ,yi=qi−qˉ
则目标函数可以改写为
F(R)=i=1∑N∥xiR−yi∥2
将所有 xi 和 yi 按行堆叠成矩阵:
X=x1x2⋮xN,Y=y1y2⋮yN
则有
F(R)=∥XR−Y∥F2
由 F范数 与迹的关系([[F范数与迹]])可得
F(R)=∥XR−Y∥F2=tr((XR−Y)T(XR−Y))
展开后
F(R)=tr(RTXTXR)−tr(RTXTY)−tr(YTXR)+tr(YTY)
又由于 RTR=I 与迹的循环不变性
tr(YTXR)=tr(RTXTY)
所以
F(R)=tr(XTX)−2tr(RTXTY)+tr(YTY)
其中 tr(XTX) 和 tr(YTY) 都与 R 无关,因此
最小化F(R)等价于最大化tr(RTXTY).
记 C=XTY,则问题转化为
Rmaxtr(RTC),s.t. RTR=I
-
求解最优旋转矩阵 R∗ 和最优平移 T∗
对矩阵 C 做 SVD 分解
C=UΣVT
其中
Σ=diag(σ1,σ2,…,σd),σi≥0
则
tr(RTC)=tr(RTUΣVT)
利用迹的循环不变性
tr(RTUΣVT)=tr(VTRTUΣ)
记 M=VTRTU ,且由于 R,U,V 都是正交矩阵,M 也为正交矩阵。
故
tr(RTC)=tr(MΣ)
在三维情景下
Σ=diag(σ1,σ2,σ3)
则
tr(MΣ)=m11σ1+m22σ2+m33σ3
由于
∣mii∣≤1,σi≥0,i=1,2,3
因此
m11σ1+m22σ2+m33σ3≤σ1+σ2+σ3
当且仅当 m11=m22=m33=1 时,等号成立
此时
M=I
于是有
VTRTU=I
从而得到最优旋转矩阵
R∗=UVT
代回 T 所对应的方程,得
T∗=qˉ−pˉR∗
-
基于现实情况对 R∗ 修正
上式得到的 R∗ 虽然满足正交性,但对于蛋白质来说,其可能不是真正的旋转矩阵。
由于
det(R∗)=det(U)det(VT)
而正交矩阵的行列式只能取 ±1 ,因此可能出现
det(R∗)=−1
此时意味着在这个变换中发生了 镜面反射 ,即蛋白质经过变换后发生了手性改变。
镜面反射指在三维空间的 x,y,z 三轴中,有一条轴被翻转,此时 R∗ 代表的不只是一个单纯的旋转矩阵。
因此,需要对 det(R∗) 的结果进行修正。
修正:在三个奇异方向中,找到翻转代价最小的那一条轴,再进行一次符号翻转
由于奇异值满足
σ1≥σ2≥σ3≥0
故选择对应最小奇异值 σ3 的方向进行进行修正。
引入
D=diag(1,1,−1)
综合来看
D=⎩⎨⎧diag(1,1,1),diag(1,1,−1),det(VUT)=1,det(VUT)=−1,(无需修正),(需要修正).
更一般的
D=diag(1,1,det(VUT))
于是修正后的 R∗ 为
R∗=VDUT
结果汇总
经修正后原问题(刚体配准问题
R,Tmini=1∑N∥piR+T−qi∥2
的解为
R∗=VDUT,T∗=qˉ−pˉR∗
其中
D=diag(1,1,det(VUT))
且
X=p1−pˉp2−pˉ⋮pN−pˉ,Y=q1−qˉq2−qˉ⋮qN−qˉ,C=XTY=UΣVT
代码实现
import numpy as np
def Kabsch(P, Q):
P = np.asarray(P, dtype = float)
Q = np.asarray(Q, dtype = float)
# Calc X & Y & C
p_cent = P.mean(axis=0)
q_cent = Q.mean(axis=0)
X = P - p_cent
Y = Q - p_cent
C = X.T @ Y
# SVD
U, Sig, Vt = np.linalg.svd(C)
V = Vt.T
# Add correction D (3-Dim)
D = np.diag([1, 1, np.sign(np.linalg.det(V @ U.T))])
# Calc R* & T*
R_star = V @ D @ U.T
T_star = q_cent - p_cent @ R_star
return R_star, T_star
若是想要返回配准后的RMSD([[RMSD]])的计算结果
def RMSD_Kabsch(P, Q):
...
P_fit = P @ R_star + T_star
rmsd = np.sqrt(np.mean(np.sum((P_fit - Q) ** 2, axis=1)))
return rmsd
相关