【问题标题】:Convert distance pairs to distance matrix to use in hierarchical clustering将距离对转换为距离矩阵以用于层次聚类
【发布时间】:2019-01-11 10:50:53
【问题描述】:

我正在尝试将字典转换为距离矩阵,然后我可以将其用作层次聚类的输入:我有作为输入:

  • 键:长度为 2 的元组与我有距离的对象
  • value:实际距离值

    for k,v in obj_distances.items():
    print(k,v)
    

结果是:

('obj1', 'obj2') 2.0 
('obj3', 'obj4') 1.58
('obj1','obj3') 1.95
('obj2', 'obj3') 1.80

我的问题是如何将其转换为距离矩阵,以便以后在 scipy 中进行聚类?

【问题讨论】:

  • 您可以先创建一个零矩阵,然后使用int(a[-1]) 作为矩阵的索引,其中a'obj1''obj2' 等,并将距离值存储在该数组中
  • 您的距离设置是否完整?也就是说,距离字典是否包含每个可能对的距离?例如,您显示的数据不包括('obj1', 'obj4')('obj2', 'obj4') 的距离。您将需要这些值来进行聚类。
  • 嗨@WarrenWeckesser,是的,我只是为了节省空间而省略了它,但是是的,我有所有成对距离,谢谢

标签: python scipy scikit-learn hierarchical-clustering


【解决方案1】:

您说您将使用 scipy 进行聚类,所以我假设这意味着您将使用函数 scipy.cluster.hierarchy.linkagelinkage 接受“压缩”形式的距离数据,因此您不必创建完整的对称距离矩阵。 (例如,请参阅 How does condensed distance matrix work? (pdist),了解关于精简形式的讨论。)

所以你所要做的就是让obj_distances.values() 进入一个已知的顺序并将它传递给linkage。这就是在下面的 sn-p 中所做的:

from scipy.cluster.hierarchy import linkage, dendrogram

obj_distances = {
    ('obj2', 'obj3'): 1.8,
    ('obj3', 'obj1'): 1.95,
    ('obj1', 'obj4'): 2.5,
    ('obj1', 'obj2'): 2.0,
    ('obj4', 'obj2'): 2.1,
    ('obj3', 'obj4'): 1.58,
}

# Put each key pair in a canonical order, so we know that if (a, b) is a key,
# then a < b.  If this is already true, then the next three lines can be
# replaced with
#     sorted_keys, distances = zip(*sorted(obj_distances.items()))
# Note: we assume there are no keys where the two objects are the same.
keys = [sorted(k) for k in obj_distances.keys()]
values = obj_distances.values()
sorted_keys, distances = zip(*sorted(zip(keys, values)))

# linkage accepts the "condensed" format of the distances.
Z = linkage(distances)

# Optional: create a sorted list of the objects.
labels = sorted(set([key[0] for key in sorted_keys] + [sorted_keys[-1][-1]]))

dendrogram(Z, labels=labels)

树状图:

【讨论】:

  • 感谢@WarrenWeckesser 正是我想要做的,感谢!
【解决方案2】:

这将比发布的其他答案慢,但会确保包含中间对角线上方和下方的值,如果这对您很重要:

import pandas as pd

unique_ids = sorted(set([x for y in obj_distance.keys() for x in y]))
df = pd.DataFrame(index=unique_ids, columns=unique_ids)

for k, v in obj_distance.items():
    df.loc[k[0], k[1]] = v
    df.loc[k[1], k[0]] = v

结果:

      obj1 obj2  obj3  obj4
obj1   NaN    2  1.95   NaN
obj2     2  NaN   1.8   NaN
obj3  1.95  1.8   NaN  1.58
obj4   NaN  NaN  1.58   NaN

【讨论】:

  • 非常感谢@thesilkworm
【解决方案3】:

使用 pandas 并取消堆叠数据框:

import pandas as pd

data = {('obj1', 'obj2'): 2.0 ,
('obj3', 'obj4'): 1.58,
('obj1','obj3'): 1.95,
('obj2', 'obj3'): 1.80,}

df = pd.DataFrame.from_dict(data, orient='index')
df.index = pd.MultiIndex.from_tuples(df.index.tolist())
dist_matrix = df.unstack().values

产量

In [15]: dist_matrix
Out[15]:

array([[2.  , 1.95,  nan],
       [ nan, 1.8 ,  nan],
       [ nan,  nan, 1.58]])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-21
    • 2012-09-05
    • 2014-10-24
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 2013-04-21
    相关资源
    最近更新 更多