在python中层次聚类的每一步打印所有聚类和样本

Posted

技术标签:

【中文标题】在python中层次聚类的每一步打印所有聚类和样本【英文标题】:Print all clusters and samples at each step of hierarchical clustering in python 【发布时间】:2021-03-10 02:04:07 【问题描述】:

我使用 Scipy 库来执行层次聚类并创建树状图。这是简单的代码和生成的树状图:

import numpy as np
from scipy.cluster.hierarchy import dendrogram, linkage
from matplotlib import pyplot as plt

X = np.array([[5, 3],
              [10, 15],
              [15, 12],
              [24, 10],
              [30, 30],
              [85, 70],
              [71, 80],
              [60, 78],
              [70, 55],
              [80, 91]])
linkage_matrix = linkage(X, "single")
_ = dendrogram(linkage_matrix,)

我需要在聚类过程的每个步骤中打印属于每个聚类的所有聚类和样本。这是上述数据和树状图的所需输出:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]

请注意,如果有使用Scikit-Learn agglomerative clustering的解决方案也可以。

【问题讨论】:

【参考方案1】:

使用同一模块中的cut_tree 函数,并指定簇数作为切割条件。不幸的是,在每个元素都是它自己的簇的情况下它不会被削减,但这种情况是微不足道的。

另外,cut_tree 返回的矩阵是这样的形状,每个 代表特定切割的组。所以我转置了矩阵,但您也可以相应地调整 for 循环

import numpy as np
from scipy.cluster.hierarchy import dendrogram, linkage, to_tree, cut_tree
from matplotlib import pyplot as plt

X = np.array([[5, 3],
              [10, 15],
              [15, 12],
              [24, 10],
              [30, 30],
              [85, 70],
              [71, 80],
              [60, 78],
              [70, 55],
              [80, 91]])
linkage_matrix = linkage(X, "single")
clusters = cut_tree(linkage_matrix, n_clusters=range(1, X.shape[0]))
print(clusters)
# insert column for the case, where every element is its own cluster
clusters = np.insert(clusters, clusters.shape[1], range(clusters.shape[0]), axis=1)
# transpose matrix
clusters = clusters.T
print(clusters)
for row in clusters[::-1]:
    # create empty dictionary
    groups = 
    for i, g in enumerate(row):
        if g not in groups:
            # add new key to dict and assign empty set
            groups[g] = set([])
        # add to set of certain group
        groups[g].add(i)
    print(list(groups.values()))

更好的解决方案

而不是两个 for 循环和cut_tree,使用对来自 links_matrix 的集合和信息的操作。 for 循环以线性时间复杂度运行,但最耗时的是print 语句

在大约 30_000 个样本的情况下,打印到文件将创建大约 30GB 的大文件。

linkage_matrix = linkage(X, "single")

dct = dict([(i, i) for i in range(X.shape[0])])
print(list(dct.values()))
for i, row in enumerate(linkage_matrix, X.shape[0]):
    dct[i] = dct[row[0]].union(dct[row[1]])
    del dct[row[0]]
    del dct[row[1]]
    print(list(dct.values()))

【讨论】:

谢谢@Mark。看来您的解决方案非常耗时,而且在内存方面也不可行。我刚刚尝试在大小为 (29000, 5) 的数据集上执行您的代码的 cut_treenp.insert 步骤,但我的笔记本电脑内存不足 16G RAM。所以,我不得不停止这个过程。您能给我提供解决此问题的任何建议或任何其他解决方案吗? @amirmasoud 我添加了更好的解决方案,内存不会成为问题。但是用 29000 个样本将它打印到控制台需要一些时间(通过注释掉打印语句,它会运行得很快)

以上是关于在python中层次聚类的每一步打印所有聚类和样本的主要内容,如果未能解决你的问题,请参考以下文章

聚类算法总结以及python代码实现

层次聚类及scipy中的层次聚类python代码解释

python大战机器学习——聚类和EM算法

聚类:层次聚类

聚类之K均值聚类和EM算法

层次聚类