Blog Post

Kabsch Algorithm

Kabsch算法的推导

  • note
  • Math
  • bio
  • python
  • RMSD
  • kabsch
  • ICP
  • SVD
  • LinearAlgebra

作者:Eric

创建时间:2026-04-16 11:06

这篇记什么

  • 量化同一序列多肽(蛋白质)相似性,使用RMSD+Kabsch算法
  • 进行Kabsch算法的推导及揭示其对应的数学原理
  • 给出算法对应的python实现

主要内容

问题提出(刚体配准问题)

设有两组组成完全相同对应点(pdb文件中的ATOM行):

piP,qiQ,i=1,2,,Np_i \in P,\qquad q_i \in Q,\qquad i=1,2,\dots,N

在经过配准后

Pfit=PR+TP_{fit} = PR + T

希望求旋转矩阵 RR 和平移向量 TT ,使得目标函数

minR,Ti=1NpiR+Tqi2\min_{R,T}\sum_{i=1}^N \|p_iR+T-q_i\|^2

达到最小,其中 RR 满足

RTR=IR^TR=I

在蛋白质结构中,一般还需令 det(R)=1det(R)=1 来保证该蛋白质不存在镜面对称构象。

求解过程

  1. 消除平移向量 TT

    定义目标函数

    F(R,T)=i=1NpiR+Tqi2F(R,T)=\sum_{i=1}^N \|p_iR+T-q_i\|^2

    TT 求偏导,并令其为零:

    FT=2i=1N(piR+Tqi)=0\frac{\partial F}{\partial T}=2\sum_{i=1}^N (p_iR+T-q_i)=0

    因此

    NT=i=1N(qipiR)NT=\sum_{i=1}^N (q_i-p_iR)

    从而

    T=1Ni=1Nqi1Ni=1NpiRT=\frac{1}{N}\sum_{i=1}^N q_i-\frac{1}{N}\sum_{i=1}^N p_iR

    记两组点的质心分别为

    pˉ=1Ni=1Npiqˉ=1Ni=1Nqi\bar p=\frac{1}{N}\sum_{i=1}^N p_i\qquad \bar q=\frac{1}{N}\sum_{i=1}^N q_i

    则平移项可改写为

    T=qˉpˉRT=\bar q-\bar pR

    TT 代入目标函数,得

    F(R)=i=1NpiR+qˉpˉRqi2F(R)=\sum_{i=1}^N \|p_iR+\bar q-\bar pR-q_i\|^2

    整理后可得

    F(R)=i=1N(pipˉ)R(qiqˉ)2F(R)=\sum_{i=1}^N \|(p_i-\bar p)R-(q_i-\bar q)\|^2
  2. 优化目标函数 F(R)F(R)

    定义去中心化后的坐标

    xi=pipˉ,yi=qiqˉx_i=p_i-\bar p,\qquad y_i=q_i-\bar q

    则目标函数可以改写为

    F(R)=i=1NxiRyi2F(R)=\sum_{i=1}^N \|x_iR-y_i\|^2

    将所有 xix_iyiy_i 按行堆叠成矩阵:

    X=[x1x2xN],Y=[y1y2yN]X=\begin{bmatrix} x_1\\ x_2\\ \vdots\\ x_N \end{bmatrix}, \qquad Y=\begin{bmatrix} y_1\\ y_2\\ \vdots\\ y_N \end{bmatrix}

    则有

    F(R)=XRYF2F(R)=\|XR-Y\|_F^2

    F范数F范数 与迹的关系([[F范数与迹]])可得

    F(R)=XRYF2=tr((XRY)T(XRY))F(R)=\|XR-Y\|_F^2=\operatorname{tr}\big((XR-Y)^T(XR-Y)\big)

    展开后

    F(R)=tr(RTXTXR)tr(RTXTY)tr(YTXR)+tr(YTY)F(R)=\operatorname{tr}(R^TX^TXR)-\operatorname{tr}(R^TX^TY)-\operatorname{tr}(Y^TXR)+\operatorname{tr}(Y^TY)

    又由于 RTR=IR^TR=I迹的循环不变性

    tr(YTXR)=tr(RTXTY)\operatorname{tr}(Y^TXR)=\operatorname{tr}(R^TX^TY)

    所以

    F(R)=tr(XTX)2tr(RTXTY)+tr(YTY)F(R)=\operatorname{tr}(X^TX)-2\operatorname{tr}(R^TX^TY)+\operatorname{tr}(Y^TY)

    其中 tr(XTX)\operatorname{tr}(X^TX)tr(YTY)\operatorname{tr}(Y^TY) 都与 RR 无关,因此

    最小化F(R)等价于最大化tr(RTXTY).\boxed{\text{最小化} F(R) \text{等价于最大化} \operatorname{tr}(R^TX^TY)}.

    C=XTYC=X^TY,则问题转化为

    maxRtr(RTC),s.t. RTR=I\max_R \operatorname{tr}(R^TC),\qquad \text{s.t. } R^TR=I
  3. 求解最优旋转矩阵 RR^\ast 和最优平移 TT^\ast

    对矩阵 CCSVDSVD 分解

    C=UΣVTC=U\Sigma V^T

    其中

    Σ=diag(σ1,σ2,,σd),σi0\Sigma=\operatorname{diag}(\sigma_1,\sigma_2,\dots,\sigma_d),\qquad \sigma_i\ge 0

    tr(RTC)=tr(RTUΣVT)\operatorname{tr}(R^TC)=\operatorname{tr}(R^TU\Sigma V^T)

    利用迹的循环不变性

    tr(RTUΣVT)=tr(VTRTUΣ)\operatorname{tr}(R^TU\Sigma V^T)=\operatorname{tr}(V^TR^TU\Sigma)

    M=VTRTUM = V^TR^TU ,且由于 R,U,VR,U,V 都是正交矩阵,MM 也为正交矩阵。

    tr(RTC)=tr(MΣ)\operatorname{tr}(R^TC)=\operatorname{tr}(M\Sigma)

    在三维情景下

    Σ=diag(σ1,σ2,σ3)\Sigma=\operatorname{diag}(\sigma_1,\sigma_2,\sigma_3)

    tr(MΣ)=m11σ1+m22σ2+m33σ3\operatorname{tr}(M\Sigma)=m_{11}\sigma_1+m_{22}\sigma_2+m_{33}\sigma_3

    由于

    mii1,σi0,i=1,2,3|m_{ii}| \le 1, \qquad \sigma_i \ge 0, \qquad i=1,2,3

    因此

    m11σ1+m22σ2+m33σ3σ1+σ2+σ3m_{11}\sigma_1+m_{22}\sigma_2+m_{33}\sigma_3 \le \sigma_1 + \sigma_2 + \sigma_3

    当且仅当 m11=m22=m33=1m_{11}=m_{22}=m_{33}=1 时,等号成立
    此时

    M=IM=I

    于是有

    VTRTU=IV^TR^TU=I

    从而得到最优旋转矩阵

    R=UVTR^\ast=UV^T

    代回 TT 所对应的方程,得

    T=qˉpˉRT^\ast=\bar q-\bar pR^\ast
  4. 基于现实情况对 RR^\ast 修正

    上式得到的 RR^\ast 虽然满足正交性,但对于蛋白质来说,其可能不是真正的旋转矩阵。 由于

    det(R)=det(U)det(VT)det(R^\ast) = det(U)det(V^T)

    而正交矩阵的行列式只能取 ±1\pm 1 ,因此可能出现

    det(R)=1det(R^\ast)=-1

    此时意味着在这个变换中发生了 镜面反射 ,即蛋白质经过变换后发生了手性改变。

    镜面反射指在三维空间的 x,y,zx , y, z 三轴中,有一条轴被翻转,此时 RR^\ast 代表的不只是一个单纯的旋转矩阵。

    因此,需要对 det(R)det(R^\ast) 的结果进行修正。

    修正:在三个奇异方向中,找到翻转代价最小的那一条轴,再进行一次符号翻转

    由于奇异值满足

    σ1σ2σ30\sigma_1\ge \sigma_2\ge \sigma_3\ge 0

    故选择对应最小奇异值 σ3\sigma_3 的方向进行进行修正。 引入

    D=diag(1,1,1)D=\operatorname{diag}(1,1,-1)

    综合来看

    D={diag(1,1,1),det(VUT)=1(无需修正),diag(1,1,1),det(VUT)=1(需要修正).D = \begin{cases} \operatorname{diag}(1,1,1), & \det(VU^T)=1, &(无需修正),\\[6pt] \operatorname{diag}(1,1,-1), & \det(VU^T)=-1, &(需要修正). \end{cases}

    更一般的

    D=diag(1,1,det(VUT))D=\operatorname{diag}\bigl(1,1,\det(VU^T)\bigr)

    于是修正后的 RR^\ast

    R=VDUTR^\ast=VDU^T

结果汇总

经修正后原问题(刚体配准问题

minR,Ti=1NpiR+Tqi2\min_{R,T}\sum_{i=1}^N \|p_iR+T-q_i\|^2

的解为

R=VDUT,T=qˉpˉRR^\ast=VDU^T,\qquad T^\ast=\bar q-\bar pR^\ast

其中

D=diag(1,1,det(VUT))D=\operatorname{diag}\bigl(1,1,\det(VU^T)\bigr)

X=[p1pˉp2pˉpNpˉ],Y=[q1qˉq2qˉqNqˉ],C=XTY=UΣVTX=\begin{bmatrix} p_1-\bar p\\ p_2-\bar p\\ \vdots\\ p_N-\bar p \end{bmatrix}, \qquad Y=\begin{bmatrix} q_1-\bar q\\ q_2-\bar q\\ \vdots\\ q_N-\bar q \end{bmatrix}, \qquad C=X^TY=U\Sigma V^T

代码实现

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

相关