55

我已经编写了自己的聚类例程,并希望生成树状图。最简单的方法是使用 scipy dendrogram 函数。但是,这要求输入与 scipy 链接函数产生的格式相同。我找不到如何格式化输出的示例。我想知道是否有人可以启发我。

4

5 回答 5

48

我同意https://stackoverflow.com/users/1167475/mortonjt文档没有完全解释中间集群的索引,而我同意https://stackoverflow.com/users/1354844/dkar格式在其他方面进行了精确解释。

使用来自此问题的示例数据:scipy.cluster.hierarchy 教程

A = np.array([[0.1,   2.5],
              [1.5,   .4 ],
              [0.3,   1  ],
              [1  ,   .8 ],
              [0.5,   0  ],
              [0  ,   0.5],
              [0.5,   0.5],
              [2.7,   2  ],
              [2.2,   3.1],
              [3  ,   2  ],
              [3.2,   1.3]])

可以使用单个(即最接近的匹配点)构建链接矩阵:

z = hac.linkage(a, method="single")

 array([[  7.        ,   9.        ,   0.3       ,   2.        ],
        [  4.        ,   6.        ,   0.5       ,   2.        ],
        [  5.        ,  12.        ,   0.5       ,   3.        ],
        [  2.        ,  13.        ,   0.53851648,   4.        ],
        [  3.        ,  14.        ,   0.58309519,   5.        ],
        [  1.        ,  15.        ,   0.64031242,   6.        ],
        [ 10.        ,  11.        ,   0.72801099,   3.        ],
        [  8.        ,  17.        ,   1.2083046 ,   4.        ],
        [  0.        ,  16.        ,   1.5132746 ,   7.        ],
        [ 18.        ,  19.        ,   1.92353841,  11.        ]])

正如文档解释的那样,n 以下的集群(这里:11)只是原始矩阵 A 中的数据点。接下来的中间集群被连续索引。

因此,集群 7 和 9(第一次合并)合并到集群 11,集群 4 和 6 合并到 12。然后观察第三行,合并集群 5(来自 A)和 12(来自未显示的中间集群 12)导致0.5 的簇内距离 (WCD)。单一方法需要新的 WCS 为 0.5,即 A[5] 与簇 12 中最近点 A[4] 和 A[6] 之间的距离。让我们检查:

 In [198]: norm([a[5]-a[4]])
 Out[198]: 0.70710678118654757
 In [199]: norm([a[5]-a[6]])
 Out[199]: 0.5

该集群现在应该是中间集群 13,随后与 A[2] 合并。因此,新的距离应该是点 A[2] 和 A[4,5,6] 之间最近的距离。

 In [200]: norm([a[2]-a[4]])
 Out[200]: 1.019803902718557
 In [201]: norm([a[2]-a[5]])
 Out[201]: 0.58309518948452999
 In [202]: norm([a[2]-a[6]])
 Out[202]: 0.53851648071345048

可以看出,其中还检查并解释了新集群的中间格式。

于 2016-12-05T21:23:58.613 回答
41

这来自scipy.cluster.hierarchy.linkage()函数文档,我认为这是对输出格式的非常清晰的描述:

返回A ( n -1) x 4 矩阵 Z。在第i次迭代中,索引为 Z[i, 0] 和 Z[i, 1] 的集群组合在一起形成集群n + i。索引小于n的集群对应于原始观测值之一。簇 Z[i, 0] 和 Z[i, 1] 之间的距离由 Z[i, 2] 给出。第四个值 Z[i, 3] 表示新形成的聚类中原始观测值的数量。

你还需要什么吗?

于 2012-06-08T21:33:20.540 回答
12

正如 dkar 指出的那样,scipy 文档是准确的……但是将返回的数据转换为可用于进一步分析的数据有点困难。

在我看来,它们应该包括以树状数据结构返回数据的能力。下面的代码将遍历矩阵并构建一棵树:

from scipy.cluster.hierarchy import linkage
import numpy as np

a = np.random.multivariate_normal([10, 0], [[3, 1], [1, 4]], size=[100,])
b = np.random.multivariate_normal([0, 20], [[3, 1], [1, 4]], size=[50,])
centers = np.concatenate((a, b),)

def create_tree(centers):
    clusters = {}
    to_merge = linkage(centers, method='single')
    for i, merge in enumerate(to_merge):
        if merge[0] <= len(to_merge):
            # if it is an original point read it from the centers array
            a = centers[int(merge[0]) - 1]
        else:
            # other wise read the cluster that has been created
            a = clusters[int(merge[0])]

        if merge[1] <= len(to_merge):
            b = centers[int(merge[1]) - 1]
        else:
            b = clusters[int(merge[1])]
        # the clusters are 1-indexed by scipy
        clusters[1 + i + len(to_merge)] = {
            'children' : [a, b]
        }
        # ^ you could optionally store other info here (e.g distances)
    return clusters

print create_tree(centers)
于 2017-01-20T06:25:03.347 回答
0

输入
输出


考虑 [input] 是您在使用返回四列矩阵的链接时有兴趣绘制齿形图的数据

column1 和 column2 - 表示按顺序形成簇

即2和3首先创建一个集群,这个集群被命名为5
(2和3代表第2行和第3行的索引)1和5是第二个形成的集群,这个集群被命名为6

第 3 列- 表示集群之间的距离

第 4 列- 表示制作这个集群涉及多少数据点

齿形图

于 2021-10-02T19:18:09.170 回答
0

这是另一段执行相同功能的代码。这个版本跟踪每个集群(node_id)的距离(大小),并确认成员的数量。

这使用了 scipy links() 函数,该函数与聚合器集群的基础相同。

from scipy.cluster.hierarchy import linkage
import copy
Z = linkage(data_x, 'ward')

n_points = data_x.shape[0]
clusters = [dict(node_id=i, left=i, right=i, members=[i], distance=0, log_distance=0, n_members=1) for i in range(n_points)]
for z_i in range(Z.shape[0]):
    row = Z[z_i]
    cluster = dict(node_id=z_i + n_points, left=int(row[0]), right=int(row[1]), members=[], log_distance=np.log(row[2]), distance=row[2], n_members=int(row[3]))
    cluster["members"].extend(copy.deepcopy(members[cluster["left"]]))
    cluster["members"].extend(copy.deepcopy(members[cluster["right"]]))
    clusters.append(cluster)

on_split = {c["node_id"]: [c["left"], c["right"]] for c in clusters}
up_merge = {c["left"]: {"into": c["node_id"], "with": c["right"]} for c in clusters}
up_merge.update({c["right"]: {"into": c["node_id"], "with": c["left"]} for c in clusters})
于 2019-02-10T17:07:31.730 回答