scipy hierarchy.linkage与Bray-Curtis距离结果不一致问题咨询
我之前处理微生物群落物种计数数据时也碰到过一模一样的问题!核心原因大多是两个库对数据格式的要求不匹配,再加上Bray-Curtis距离/相似度的细节容易搞混,咱们一步步拆解解决:
1. 最常见的坑:距离矩阵格式不兼容
scikit-bio的pw_distance返回的是n×n的对称距离矩阵(每个元素对应一对站点的距离),但scipy的linkage函数默认不接受这种完整矩阵——它需要的是压缩的一维距离向量(也就是把对称矩阵的上三角部分按行展开成一维数组)。如果直接把完整矩阵传给linkage,它会错误地把矩阵当成样本特征来聚类,结果自然完全不对。
解决代码示例:
from scipy.spatial.distance import squareform from scipy.cluster.hierarchy import linkage import skbio # 假设你从scikit-bio得到的距离矩阵是skbio_dist_mat # 如果是DistanceMatrix对象,先转成numpy数组 if isinstance(skbio_dist_mat, skbio.stats.distance.DistanceMatrix): dist_array = skbio_dist_mat.to_array() else: dist_array = skbio_dist_mat # 把对称矩阵转换成linkage需要的压缩向量 compressed_dist = squareform(dist_array, checks=False) # 选择群落分析常用的UPGMA聚类方法(average) Z = linkage(compressed_dist, method='average')
2. 确认是距离还是相似度
Bray-Curtis的取值范围是0到1,但要注意两个核心概念:
- 相似度:越接近1,两个站点的物种组成越相似
- 距离:越接近0,两个站点的物种组成越相似
scikit-bio的pw_distance默认返回的是距离(即1 - 相似度),但如果你手动调整过参数或混淆了概念,就会出问题。比如如果你的矩阵实际是相似度,直接传给linkage会导致聚类逻辑完全颠倒。
验证与修正:
# 检查矩阵取值的含义 if dist_array.max() <= 1 and dist_array.min() >= 0: # 如果是相似度,转成距离(linkage基于距离聚类) dist_array = 1 - dist_array # 再转成压缩向量 compressed_dist = squareform(dist_array) Z = linkage(compressed_dist, method='average')
3. 聚类方法的选择差异
scipy的linkage默认用的是single(单链接)聚类方法,而微生物群落研究中常用的是average(UPGMA)或ward方法。不同的聚类方法会生成完全不同的树状图,这也会让你误以为“结果不一致”。
建议:明确你需要的聚类方法,比如:
# UPGMA聚类(群落分析常用) Z = linkage(compressed_dist, method='average') # 或者Ward法(适合方差最小化的聚类) Z = linkage(compressed_dist, method='ward')
4. 样本顺序一致性检查
最后要确认scikit-bio返回的距离矩阵的站点顺序,和你后续绘制树状图时标注的站点顺序完全一致。可以通过scikit-bio的DistanceMatrix对象的ids属性查看:
if isinstance(skbio_dist_mat, skbio.stats.distance.DistanceMatrix): print("站点顺序:", skbio_dist_mat.ids)
如果顺序不对,即使聚类正确,树状图的标注也会看起来混乱。
用以上步骤排查后,应该就能得到和预期一致的聚类树状图了。我当时就是因为直接把完整矩阵传给了linkage,踩了这个大坑😂
内容的提问来源于stack exchange,提问作者user2619065

