层次聚类(Hierarchical Clustering)是一种重要的聚类方法,它通过不断合并或分裂数据点的方式,生成一个层次结构(Dendrogram)来表示数据之间的相似性。与其他聚类方法(如K均值聚类)不同,层次聚类不需要预先指定聚类的数量,这使得它在许多实际问题中非常适用,特别是当数据的自然聚类数目不明确时。 层次聚类有两种主要类型:凝聚型层次聚类(Agglomerative Clustering)和分裂型层次聚类(Divisive Clustering)。凝聚型层次聚类是从每个数据点开始,逐步合并最相似的簇,直到所有数据点合并为一个簇。分裂型层次聚类则从一个整体簇开始,逐步分裂成更小的簇,直到每个数据点都是一个独立的簇。
层次聚类是一种通过递归合并(凝聚型)或递归分裂(分裂型)数据点的方式,逐步构建出一个层次结构的聚类方法。层次聚类的结果通常通过**树状图(Dendrogram)**表示,它可以直观地显示数据点之间的相似性或距离关系。
层次聚类分为两种主要形式:
凝聚型层次聚类是一个自底向上的过程。从每个数据点作为一个簇开始,不断合并相似的簇,直到所有样本都属于同一个簇或满足停止条件。
凝聚型层次聚类的算法可以总结为以下几个步骤:
开始时,每个数据点都被当作一个簇。即每个数据点是一个簇,这时簇的数目等于样本数。
在每次迭代中,需要计算所有簇之间的距离。距离的计算可以使用多种方式,最常见的有:
在每一次迭代中,找到距离最小的两个簇,将它们合并为一个簇。
合并两个簇后,需要更新簇间的距离矩阵,重新计算新簇与其他簇之间的距离。
继续合并最相似的簇,直到满足停止条件。停止条件通常是聚类数目达到指定值,或者所有样本点都被归为一个簇。
在凝聚型层次聚类中,簇与簇之间的距离是决定是否合并的关键。常见的计算方式有:
单链接方法中,簇间的距离定义为两个簇中最近的点之间的距离。公式为:
其中,A 和 B 为两个簇,
和
是簇 A 和簇 B 中的样本,
是它们之间的距离。
全链接方法中,簇间的距离定义为两个簇中最远的点之间的距离。公式为:
平均链接方法中,簇间的距离定义为所有样本点之间距离的平均值。公式为:
中心链接方法中,簇间的距离是两个簇的质心(即簇内样本点的平均值)之间的距离。公式为:
其中,
和
是簇 A 和 B 的质心。
以下是一个完整的 凝聚型层次聚类(Agglomerative Hierarchical Clustering) 的 Python 实现。此实现使用 scipy
和 numpy
来完成数据的聚类,并使用 matplotlib
来进行结果的可视化。
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial.distance import pdist, squareform
# 计算每两个簇之间的距离
def compute_distance_matrix(X):
"""
计算样本点之间的距离矩阵
"""
return squareform(pdist(X, metric='euclidean')) # 计算欧氏距离矩阵
# 凝聚型层次聚类
def agglomerative_clustering(X, n_clusters=2):
"""
凝聚型层次聚类实现
:param X: 数据集 (n_samples, n_features)
:param n_clusters: 目标聚类数量
:return: 每个数据点的簇标签
"""
# 初始化每个数据点是一个单独的簇
clusters = [[i] for i in range(len(X))]
distance_matrix = compute_distance_matrix(X) # 初始化距离矩阵
# 迭代直到剩下目标数量的簇
while len(clusters) > n_clusters:
# 寻找距离最近的两个簇
min_dist = np.inf
cluster_a, cluster_b = None, None
for i in range(len(clusters)):
for j in range(i + 1, len(clusters)):
dist = np.min(distance_matrix[clusters[i], :][:, clusters[j]]) # 计算两个簇之间的最小距离
if dist < min_dist:
min_dist = dist
cluster_a, cluster_b = clusters[i], clusters[j]
# 合并两个簇
new_cluster = cluster_a + cluster_b
clusters.remove(cluster_a)
clusters.remove(cluster_b)
clusters.append(new_cluster)
# 更新距离矩阵
new_dist_row = np.min(distance_matrix[cluster_a, :][:, cluster_b], axis=1) # 计算合并后的簇与其他簇的距离
distance_matrix = np.delete(distance_matrix, cluster_b, axis=0) # 删除已合并簇的行
distance_matrix = np.delete(distance_matrix, cluster_b, axis=1) # 删除已合并簇的列
distance_matrix = np.column_stack((distance_matrix, new_dist_row)) # 添加新簇的距离列
new_dist_col = np.append(new_dist_row, np.inf) # 新簇与其他簇的距离
distance_matrix = np.row_stack((distance_matrix, new_dist_col)) # 添加新簇的距离行
# 返回聚类结果
labels = np.zeros(len(X))
for idx, cluster in enumerate(clusters):
for sample in cluster:
labels[sample] = idx
return labels
# 示例数据
np.random.seed(0)
X = np.random.rand(10, 2) # 10个二维数据点
# 执行凝聚型层次聚类
n_clusters = 3
labels = agglomerative_clustering(X, n_clusters=n_clusters)
# 可视化结果
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=50)
plt.title(f'Agglomerative Hierarchical Clustering (n_clusters={n_clusters})')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
def compute_distance_matrix(X):
"""
计算样本点之间的距离矩阵
"""
return squareform(pdist(X, metric='euclidean')) # 计算欧氏距离矩阵
pdist
计算所有点之间的成对距离,squareform
将它转化为对称矩阵。def agglomerative_clustering(X, n_clusters=2):
"""
凝聚型层次聚类实现
:param X: 数据集 (n_samples, n_features)
:param n_clusters: 目标聚类数量
:return: 每个数据点的簇标签
"""
在每一轮合并中,我们计算两个簇之间的最小距离,找到最相似的簇并将它们合并。在合并后,我们更新距离矩阵,删除已合并簇的行和列,并计算新簇与其他簇的距离。
合并操作完成后,clusters
变量中存储了每个簇的样本索引。通过遍历这些簇并为每个簇中的点分配一个唯一的标签,最终返回所有样本的簇标签。
# 可视化结果
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=50)
plt.title(f'Agglomerative Hierarchical Clustering (n_clusters={n_clusters})')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()
matplotlib
绘制了二维数据点的散点图,并为不同簇的点使用不同的颜色表示。c=labels
会根据聚类结果为每个点分配不同的颜色。运行该代码后,您将看到一个二维的散点图,其中每个数据点根据所属的簇被不同颜色标记。图中的 n_clusters=3
表示我们设置了3个簇。如果您修改 n_clusters
参数,可以观察不同簇数下的聚类效果。
凝聚型层次聚类是一种自下而上的聚类方法,它逐步将最相似的簇合并成一个层次结构,直至所有数据点合并为一个簇。尽管该方法计算复杂度较高,但其生成的层次树可以为数据提供丰富的层次信息,帮助理解数据的结构和内在关系。凝聚型层次聚类适用于那些不确定簇数、数据具有层次结构或簇的形态复杂的情况,是一种非常有用的聚类方法。