You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中基于预计算距离实现层次凝聚聚类

基于预计算距离实现层次凝聚聚类方案

核心实现逻辑

不管是scipy还是sklearn的层次聚类接口,都支持直接输入预计算的距离,不需要原始特征数据,你查到的需要原始数据的用法是默认用内置距离指标的场景。

步骤1:将成对距离数据转换为标准输入格式

你现有存储为字典列表的成对距离,需要先转换为两种格式之一:

  • 紧凑距离矩阵(Condensed Distance Matrix):长度为n*(n-1)/2的一维数组,存储所有i<j的样本对距离,为scipy的linkage接口标准输入
  • 方阵形式距离矩阵:n*n的二维数组,dist[i][j]为样本i和样本j的距离,对角线为0,为sklearn的预计算距离场景标准输入

代码示例:

import numpy as np
from scipy.cluster.hierarchy import linkage, dendrogram
from sklearn.cluster import AgglomerativeClustering

# 你的原始预计算距离数据
data = [
    {'id1': 1, 'id2': 2, 'dist': 3},
    {'id1': 1, 'id2': 3, 'dist': 2},
    {'id1': 2, 'id2': 3, 'dist': 4}
]

# 映射原始ID到连续索引(方便矩阵对齐)
all_ids = sorted({d['id1'] for d in data} | {d['id2'] for d in data})
id_to_idx = {id_val: idx for idx, id_val in enumerate(all_ids)}
n_samples = len(all_ids)

# 生成方阵形式距离矩阵
square_dist = np.zeros((n_samples, n_samples))
for item in data:
    i = id_to_idx[item['id1']]
    j = id_to_idx[item['id2']]
    square_dist[i][j] = square_dist[j][i] = item['dist']

# 如需生成紧凑距离矩阵,直接调用scipy工具方法即可
from scipy.spatial.distance import squareform
condensed_dist = squareform(square_dist)

步骤2:执行层次聚类(和R的hclust效果等价)

用scipy的linkage接口可以输出和Rhclust()完全一致的聚类树合并矩阵,还支持直接绘制树状图:

# 全连接(complete linkage)聚类,对应R hclust(method='complete')
merge_matrix = linkage(condensed_dist, method='complete')

# 可选:绘制聚类树状图
import matplotlib.pyplot as plt
plt.figure(figsize=(8,4))
dendrogram(merge_matrix, labels=all_ids)
plt.show()

如果需要直接得到指定簇数的分类标签,可以用sklearn的接口,注意指定metric='precomputed':

# 示例:聚为2类,使用全连接
clust = AgglomerativeClustering(
    n_clusters=2,
    metric='precomputed',
    linkage='complete'
)
labels = clust.fit_predict(square_dist)
# 标签映射回原始ID
id_to_label = {all_ids[i]: labels[i] for i in range(n_samples)}

可选的链接方法说明

除了要求的全连接,常用链接方法还有:

  • single:单连接,取两个簇之间所有样本对的最小距离
  • average:平均连接,取两个簇之间所有样本对距离的平均值
  • centroid:质心连接,取两个簇的质心之间的距离
  • ward:沃德方差最小化,仅支持欧氏距离,非欧氏预计算距离不可用
  • median:中位连接,为质心连接的变体,降低大簇对距离计算的影响

补充:未提前预计算全量距离的处理方式

如果你还没有计算完全部成对距离,只需要把自定义的距离函数传给pdist接口,会自动完成全量距离计算:

from scipy.spatial.distance import pdist
# objs为所有待聚类的自定义类对象的列表
condensed_dist = pdist(objs, metric=objectclass.calculate_distance)
# 后续直接用linkage聚类即可

内容的提问来源于stack exchange,提问作者Max Candocia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 02:27:02