分子相似性度量:Tanimoto系数、Dice系数、余弦相似度
做药物相似性计算,说白了就是测两个分子“长得像不像”。我入行那会儿,导师丢给我一个指纹文件和一套公式,说:“你把这100万个分子对跑完。” 我盯着屏幕,心里想的是——哪种度量最靠谱?
今天咱们就把三个最常用的度量一次说透:Tanimoto系数、Dice系数和余弦相似度。它们都能算相似性,但脾气完全不同。
1. Tanimoto系数
这是圈里用得最多的系数,也叫Jaccard系数。它的核心逻辑很简单:只看两个分子共同拥有的特征,不看都不拥有的。
公式长这样(假设指纹是位向量):
T = |A ∩ B| / (|A ∪ B|)
= 共同非零位数量 / 总非零位数量
举个数值例子:A有3个位为1,B有4个位为1,其中2个是共有的。那么T = 2 / (3+4-2) = 2/5 = 0.4。
我个人习惯拿它做初筛。为什么?因为它对“稀疏”很敏感。两个分子如果不活跃的特征都很多,但活跃特征交集小,Tanimoto会给你一个诚实的低分。我在项目中遇到过,用Tanimoto筛完的top-100候选,实验命中率比余弦高出一大截。
2. Dice系数
Dice和Tanimoto长得像,但分母不一样:
D = 2 * |A ∩ B| / (|A| + |B|)
= 2 × 共同非零位 / (A非零位数量 + B非零位数量)
它给了共同特征双倍权重。我刚开始做虚拟筛选时不理解,为什么Dice分数总是比Tanimoto高一点?你想想看,分母里没有减去交集,所以当交集占主导时,Dice会“膨胀”。
Dice在化学信息学里常用于分子对接后处理和相似性融合。我个人的经验是:当指纹很稠密(比如MACCS指纹166位,平均一半是1),Dice和Tanimoto排名差异不大;但要是用ECFP4这种稀疏指纹(2048位,活跃特征只有几十个),差异就明显了。
3. 余弦相似度
余弦相似度来自向量空间模型:
cos(A, B) = (A · B) / (||A|| × ||B||)
= 点积 / (模长乘积)
对于二进制指纹,分子完全相同:cos = 1;完全不同:cos = 0。但注意,它不考虑特征的总数差异——比如A有10个活性位,B有100个活性位,只要它们的夹角小,余弦就会给高分。
我记得有个项目,用余弦排序后,一个只有2个关键位、另一个有30个关键位的两个分子,居然被排到了前10。后来发现是余弦对“尺度”不敏感。那怎么办?我通常的做法是:余弦只用在已经做过归一化的特征向量上,比如用σ-π值或物化性质向量,而不是原始指纹位。
4. 三种系数对比
| 度量 | 公式(位向量形式) | 值域 | 特点 |
|---|---|---|---|
| Tanimoto | |A∩B| / (|A|+|B|-|A∩B|) | [0, 1] | 最常用,对稀疏特征公平 |
| Dice | 2|A∩B| / (|A|+|B|) | [0, 1] | 给共同特征更高权重,分数偏高 |
| 余弦 | (A·B) / sqrt((A·A) × (B·B)) | [0, 1] | 忽略尺度差异,适合连续特征向量 |
从代码实现看,它们都可以用指纹位操作快速计算。下面是一个Python示例:
def tanimoto(fp_a, fp_b):
a = set(fp_a.bitlist())
b = set(fp_b.bitlist())
common = len(a & b)
total = len(a | b)
return common / total if total != 0 else 0.0
def dice(fp_a, fp_b):
a = set(fp_a.bitlist())
b = set(fp_b.bitlist())
common = len(a & b)
return 2 * common / (len(a) + len(b)) if (len(a)+len(b)) != 0 else 0.0
def cosine(fp_a, fp_b):
dot = sum(1 for i in range(len(fp_a)) if fp_a[i] and fp_b[i])
norm_a = sum(fp_a)
norm_b = sum(fp_b)
return dot / (sqrt(norm_a * norm_b) + 1e-10)
DataStructs.TanimotoSimilarity()和DataStructs.DiceSimilarity(),别自己造轮子。但余弦相似度RDKit没直接提供,上面的代码正好补上。
最后,放一张我常画的对比图,把三种度量的关系理清楚:
嗯,上面这张图把它们的流程串起来了。你可能会问:实际项目里怎么选?我的建议是:
- 标准虚拟筛选:用Tanimoto,业界基准,审稿人认。
- 相似性融合:Dice+权重调和,我试过效果不错。
- 跨描述子比较(比如把ECFP和物化性质拼成一个向量):用余弦,因为它不怕特征量纲不同。
三种度量就像三把刀——切不同的菜用不同的刀。你要是也踩过坑,或者有自己偏好的场景,欢迎在课后来找我聊聊。