层次聚类分析示例

层次聚类是一种常用的数据聚类方法,它通过构建一个层次嵌套的聚类树来组织数据。在这个示例中,将探讨不同距离度量对层次聚类结果的影响。将使用波形数据,这些数据可以被视为高维向量。实际上,在高维空间中,不同距离度量之间的差异通常更加明显(特别是欧几里得距离和曼哈顿距离)。

生成了三组波形数据。其中两组波形(波形1和波形2)是成比例的。余弦距离对数据的缩放是不变的,因此它无法区分这两个波形。因此,即使没有噪声,使用这种距离进行聚类也不会将波形1和2分开。

向这些波形添加了观测噪声。生成了非常稀疏的噪声:只有6%的时间点包含噪声。因此,这种噪声的l1范数(即“曼哈顿”距离)比它的l2范数(“欧几里得”距离)要小得多。这可以从类间距离矩阵中看出:对角线上的值,表征类的分布,对于欧几里得距离来说比对于曼哈顿距离要大得多。

当对数据进行聚类时,发现聚类反映了距离矩阵中的内容。实际上,对于欧几里得距离,由于噪声,类别之间的分离不好,因此聚类没有将波形分开。对于曼哈顿距离,分离效果很好,波形类别被成功恢复。最后,余弦距离根本没有将波形1和2分开,因此聚类将它们归为同一类。

代码实现

import matplotlib.patheffects as PathEffects import matplotlib.pyplot as plt import numpy as np from sklearn.cluster import AgglomerativeClustering from sklearn.metrics import pairwise_distances np.random.seed(0) # 生成波形数据 n_features = 2000 t = np.pi * np.linspace(0, 1, n_features) def sqr(x): return np.sign(np.cos(x)) X = list() y = list() for i, (phi, a) in enumerate([(0.5, 0.15), (0.5, 0.6), (0.3, 0.2)]): for _ in range(30): phase_noise = 0.01 * np.random.normal() amplitude_noise = 0.04 * np.random.normal() additional_noise = 1 - 2 * np.random.rand(n_features) # 使噪声稀疏 additional_noise[np.abs(additional_noise) < 0.997] = 0 X.append(12 * ((a + amplitude_noise) * (sqr(6 * (t + phi + phase_noise))) + additional_noise)) y.append(i) X = np.array(X) y = np.array(y) n_clusters = 3 labels = ("波形1", "波形2", "波形3") colors = ["#f7bd01", "#377eb8", "#f781bf"] # 绘制真实标签 plt.figure() plt.axes([0, 0, 1, 1]) for l, color, n in zip(range(n_clusters), colors, labels): lines = plt.plot(X[y == l].T, c=color, alpha=0.5) lines[0].set_label(n) plt.legend(loc="best") plt.axis("tight") plt.axis("off") plt.suptitle("真实情况", size=20, y=1) # 绘制距离 for index, metric in enumerate(["cosine", "euclidean", "cityblock"]): avg_dist = np.zeros((n_clusters, n_clusters)) plt.figure(figsize=(5, 4.5)) for i in range(n_clusters): for j in range(n_clusters): avg_dist[i, j] = pairwise_distances(X[y == i], X[y == j], metric=metric).mean() avg_dist /= avg_dist.max() for i in range(n_clusters): for j in range(n_clusters): t = plt.text(i, j, "%5.3f" % avg_dist[i, j], verticalalignment="center", horizontalalignment="center") t.set_path_effects([PathEffects.withStroke(linewidth=5, foreground="w", alpha=0.5)]) plt.imshow(avg_dist, interpolation="nearest", cmap="cividis", vmin=0) plt.xticks(range(n_clusters), labels, rotation=45) plt.yticks(range(n_clusters), labels) plt.colorbar() plt.suptitle("类间 %s 距离" % metric, size=18, y=1) plt.tight_layout() # 绘制聚类结果 for index, metric in enumerate(["cosine", "euclidean", "cityblock"]): model = AgglomerativeClustering(n_clusters=n_clusters, linkage="average", metric=metric) model.fit(X) plt.figure() plt.axes([0, 0, 1, 1]) for l, color in zip(np.arange(model.n_clusters), colors): plt.plot(X[model.labels_ == l].T, c=color, alpha=0.5) plt.axis("tight") plt.axis("off") plt.suptitle("层次聚类(metric=%s)" % metric, size=20, y=1) plt.show()

以上代码展示了如何使用Python中的scikit-learn库进行层次聚类分析。首先,生成了三组波形数据,并添加了稀疏噪声。然后,使用不同的距离度量(余弦距离、欧几里得距离和曼哈顿距离)来计算类间距离,并绘制了距离矩阵。最后,使用层次聚类算法对数据进行聚类,并展示了聚类结果。

从结果中可以看出,不同的距离度量对聚类结果有显著影响。在本例中,曼哈顿距离能够更好地分离波形类别,而余弦距离则无法区分波形1和2。这说明在进行层次聚类分析时,选择合适的距离度量是非常重要的。

层次聚类是一种非常灵活的聚类方法,可以应用于各种不同的数据集和问题。通过调整距离度量和聚类参数,可以探索数据的不同结构和模式。此外,层次聚类还可以与其他聚类方法(如K-means)结合使用,以提高聚类性能和可解释性。

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