层次聚类分析:结构与非结构

层次聚类是一种常用的数据聚类方法,它不需要预先指定聚类的数量,而是通过逐步合并或分裂的方式构建一个聚类树。在本例中,将探讨在数据中施加连接图以捕获局部结构的效果。连接图简单地说是20个最近邻的图。施加连接图有两个主要优势:首先,使用稀疏连接矩阵的聚类通常速度更快;其次,当使用连接矩阵时,单链接平均链接完全链接是不稳定的,并且倾向于创建几个迅速增长的聚类。实际上,平均链接和完全链接通过考虑两个聚类之间的所有距离来合并它们,从而对抗这种渗透行为,而单链接则通过仅考虑聚类之间的最短距离来夸大这种行为。连接图打破了平均链接和完全链接的这种机制,使它们更类似于更脆弱的单链接。对于非常稀疏的图,这种效果更加明显(尝试减少kneighbors_graph中的邻居数量),尤其是完全链接。特别是,图中的邻居数量非常少,会施加一种接近单链接的几何形状,这是众所周知的具有这种渗透不稳定性的。

为了生成样本数据,首先创建了一个包含1500个样本的数据集,这些样本分布在一个螺旋形的路径上,并且加入了一些随机噪声。然后,创建了一个捕捉局部连接性的图,邻居数量的多少会影响聚类结果的均匀性和计算时间。邻居数量较多会得到更均匀的聚类,但可能会忽略数据的局部流形结构。

在本例中,使用了四种不同的链接方法:平均链接完全链接、Ward链接和单链接。对于每种链接方法,都分别在有无连接图的情况下进行了聚类,并计算了每种方法的运行时间。通过比较不同链接方法和不同连接图设置下的聚类结果,可以更好地理解连接图对聚类结果的影响。

以下是实现这一聚类分析的Python代码示例:

import time import matplotlib.pyplot as plt import numpy as np from sklearn.cluster import AgglomerativeClustering from sklearn.neighbors import kneighbors_graph # 生成样本数据 n_samples = 1500 np.random.seed(0) t = 1.5 * np.pi * (1 + 3 * np.random.rand(1, n_samples)) x = t * np.cos(t) y = t * np.sin(t) X = np.concatenate((x, y)) X += 0.7 * np.random.randn(2, n_samples) X = X.T # 创建捕捉局部连接性的图 knn_graph = kneighbors_graph(X, 30, include_self=False) for connectivity in (None, knn_graph): for n_clusters in (30, 3): plt.figure(figsize=(10, 4)) for index, linkage in enumerate(("average", "complete", "ward", "single")): plt.subplot(1, 4, index + 1) model = AgglomerativeClustering(linkage=linkage, connectivity=connectivity, n_clusters=n_clusters) t0 = time.time() model.fit(X) elapsed_time = time.time() - t0 plt.scatter(X[:, 0], X[:, 1], c=model.labels_, cmap=plt.cm.nipy_spectral) plt.title("linkage=%s\n(time %.2f s)" % (linkage, elapsed_time), fontdict=dict(verticalalignment="top")) plt.axis("equal") plt.axis("off") plt.subplots_adjust(bottom=0, top=0.83, wspace=0, left=0, right=1) plt.suptitle("n_cluster=%i, connectivity=%r" % (n_clusters, connectivity is not None), size=17) plt.show()

通过上述代码,可以看到在不同的链接方法和连接图设置下,聚类结果的分布情况。这有助于理解不同链接方法的特点以及连接图对聚类结果的影响。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485