使用scikit-learn HDBSCAN计算medoid时触发ValueError错误求助
问题描述
我有一个预计算的方形距离矩阵,想通过HDBSCAN计算medoid。按照scikit-learn文档,设置store_centers="medoid"并调用.medoids_属性,但运行时触发以下错误:
Traceback (most recent call last): File "C:\Users\Desktop\Clustering\Model.py", line 163, in <module> cluster(df, 'test.txt') File "C:\Users\Desktop\Clustering\Model.py", line 139, in cluster clustering = hdb.fit(distance_matrix.tocsr()) File "C:\Users\Desktop\Clustering\venv\lib\site-packages\sklearn\cluster\_hdbscan\hdbscan.py", line 854, in fit self._weighted_cluster_center(X) in _weighted_cluster_center dist_mat = pairwise_distances( File "C:\Users\Desktop\Clustering\venv\lib\site-packages\sklearn\metrics\pairwise.py", line 2157, in pairwise_distances X, _ = check_pairwise_arrays( File "C:\Users\Desktop\Clustering\venv\lib\site-packages\sklearn\metrics\pairwise.py", line 184, in check_pairwise_arrays raise ValueError( ValueError: Precomputed metric requires shape (n_queries, n_indexed). Got (9, 2292) for 9 indexed.
我搞不懂为什么自己的方形预计算矩阵会变成9×2292的数组。除此之外模型运行正常,我也能手动通过MSE操作获取medoid。我希望通过这种方式获取每个簇的可变eps,从而把更多数据拟合到簇中。
补充代码示例:
from fuzzywuzzy import fuzz from sklearn.cluster import HDBSCAN from scipy.sparse import lil_matrix import itertools def dis_matrix(word_list): count = 0 kw_index = {} index_kw = {} n = len(word_list) distance_matrix = lil_matrix((n, n)) for kw in word_list: kw_index[kw] = count index_kw[count] = kw count += 1 for x, y in itertools.product(word_list,word_list): d = fuzz.ratio(x,y) / 100 distance = 1 - d if d <= 1 else 0.00000000000001 index1 = kw_index[x] index2 = kw_index[y] distance_matrix[index1, index2] = distance distance_matrix[index2, index1] = distance return distance_matrix, index_kw CLUSTERING_MIN_SAMPLES = 2 x = ['apple', 'app', 'banana', 'bannana', 'applesauce', 'peaches', 'peach', "appban"] distance_matrix, index_kw = dis_matrix(x) hdb = HDBSCAN(cluster_selection_epsilon=.1, metric='precomputed', n_jobs=8, min_samples=CLUSTERING_MIN_SAMPLES,store_centers='medoid') clustering = hdb.fit(distance_matrix.tocsr()) print(clustering.medoids_)
问题分析与解决
错误原因
HDBSCAN的store_centers='medoid'逻辑存在设计缺陷:当使用预计算距离矩阵时,它不会直接复用已有的距离数据,反而会尝试基于原始特征重新计算距离。但你传入的是距离矩阵而非原始特征,这导致它误将距离矩阵当成特征矩阵,进而在计算medoid时尝试对这个"特征矩阵"重新计算距离,最终出现形状不匹配的错误。
解决方案
有两种可行途径:
- 手动计算medoid:遍历每个簇内的样本,找到使簇内平均距离最小的样本作为medoid。这种方式完全避开HDBSCAN的内置medoid计算逻辑,不会触发错误,也是你当前已验证可行的方案。
- 适配HDBSCAN内置逻辑:如果坚持要用
.medoids_属性,需要在拟合时同时传入原始特征矩阵和预计算的距离矩阵。具体操作:- 将你的单词列表转换为可计算距离的特征矩阵(比如TF-IDF向量、词嵌入向量等,不能直接传字符串列表)
- 修改拟合代码为:
clustering = hdb.fit(X=原始特征矩阵, X_precomputed=distance_matrix.tocsr())
关于可变eps的需求
HDBSCAN的cluster_selection_epsilon参数本身用于控制簇的最小密度阈值,结合medoid计算可辅助调整簇范围。如果用手动计算medoid的方式,可以基于每个medoid的簇内距离分布,动态调整对应簇的eps值,从而纳入更多相似样本。
内容的提问来源于stack exchange,提问作者sadboy_hdbscan
相关产品推荐
相关产品推荐

