前言
提醒:
文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。
其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。
文章目录
- 前言
- 聚类算法
- 经典应用场景
- 层次聚类
- 优点
- 缺点
- 总结
- 简单实例(函数库实现)
- 数学表达
- 凝聚型层次聚类(Agglomerative Hierarchical Clustering)
- 分裂型层次聚类(Divisive Hierarchical Clustering)
- 1. 初始化
- 2. 选择分裂簇
- 4. 分裂方法
- 5. 更新簇的数量
- 6. 迭代过程
- 7. 结果表示
- 备注
- 手动实现
- 代码分析
- distance = euclidean_distance(point1, point2)
- agglomerative_clustering(points, distance_threshold=5)中distance_threshold
聚类算法
聚类算法在各种领域中有广泛的应用,主要用于发现数据中的自然分组和模式。以下是一些常见的应用场景以及每种算法的优缺点:
经典应用场景
-
市场细分:根据消费者的行为和特征,将他们分成不同的群体,以便进行有针对性的营销。
-
图像分割: 将图像划分为多个区域或对象,以便进行进一步的分析或处理。
-
社交网络分析:识别社交网络中的社区结构。
-
文档分类:自动将文档分组到不同的主题或类别中。
-
异常检测识别数据中的异常点或异常行为。
-
基因表达分析:在生物信息学中,根据基因表达模式对基因进行聚类。
层次聚类
层次聚类
层次聚类(Hierarchical
Clustering)是一种聚类分析方法,通过构建一个树状结构(或树形图),将数据集中的样本分组。层次聚类有两种主要类型:凝聚型(自下而上)和分裂型(自上而下)。以下是层次聚类的优缺点:优点
直观易理解:层次聚类通过树形图(Dendrogram)展示聚类结构,使得结果更直观易懂,方便分析数据之间的关系。
无需预先指定聚类数:与K-Means等方法不同,层次聚类不需要用户提前指定聚类的数量。用户可以根据树形图的结构选择适合的聚类数。
适用于各种类型的数据:可以处理任意类型的距离度量(如欧几里得距离、曼哈顿距离等),也可以应用于不规则形状的聚类。
适合小规模数据集:在小规模数据集上表现良好,可以提供更细致的聚类结果。
可嵌套的聚类结果:层次聚类可以生成不同层次的聚类,用户可以根据不同的需求选择不同的聚类层次。缺点
计算复杂度高:层次聚类的时间复杂度通常为 O ( n 3 ) O(n^3) O(n3) 或 O ( n 2 log n ) O(n^2 \log n) O(n2logn),因此在大规模数据集上可能会表现得非常缓慢。
对噪声和离群点敏感:层次聚类对数据中的噪声和离群点非常敏感,这可能会影响最终的聚类结果。
难以处理非球形簇:尽管层次聚类可以处理不同形状的聚类,但在实际应用中,很多实现仍然假设簇是球形的,因此对某些复杂形状的簇处理不佳。
合并或分裂的不可逆性:在凝聚型层次聚类中,一旦两个簇被合并,就无法再分开。这可能导致最终聚类结果不够灵活和准确。
选择距离度量和合并准则的挑战:层次聚类的结果对所选择的距离度量和合并准则(如单连接、全连接、平均连接等)非常敏感,不同的选择可能导致完全不同的聚类结果。总结
层次聚类是一种强大且直观的聚类方法,适合小规模数据集和探索性数据分析。然而,由于其计算复杂度高、对噪声敏感以及合并不可逆性等缺点,在处理大规模数据集或需要高效实时处理的场景中可能不够理想。在选择层次聚类时,用户应考虑数据的规模、特性以及所需的聚类精度。
简单实例(函数库实现)
import numpy as np
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import dendrogram, linkage
# 生成随机数据
np.random.seed(42)
data = np.random.rand(10, 2) # 生成10个二维随机点
# 打印生成的数据点
print("Generated Data Points:")
print(data)
# 进行层次聚类
linked = linkage(data, method='ward') # 使用Ward方法进行聚类
# 绘制树形图
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.scatter(data[:, 0], data[:, 1], c='black')
# 在每个点旁边添加编号
for i, (x, y) in enumerate(zip(data[:, 0], data[:, 1])):plt.text(x, y, str(i), fontsize=15, ha='right')
plt.title('First Scatter Plot')
plt.xlabel('X Axis')
plt.ylabel('Y Axis')
plt.subplot(1, 2, 2)
dendrogram(linked, orientation='top', distance_sort='descending', show_leaf_counts=True)
plt.title("Hierarchical Clustering Dendrogram")
plt.xlabel("Sample index")
plt.ylabel("Distance")
plt.show()#我们使用numpy生成10个二维的随机点,进行聚类分析。使用scipy.cluster.hierarchy.linkage函数
#进行层次聚类。在这个例子中,使用ward了方法,该方法最小化聚类间的方差。
data数据分布与代码运行结果:
数学表达
层次聚类(Hierarchical Clustering)是一种将数据点逐步合并成类的聚类方法,形成一个树状结构(树形图,dendrogram)。它可以分为两种主要类型:凝聚型(Agglomerative)和分裂型(Divisive)。下面将结合数学表达式对其进行详细讲解。
凝聚型层次聚类(Agglomerative Hierarchical Clustering)
以下是凝聚型层次聚类的数学描述:
1. 初始化
假设有 n n n 个数据点 X = { x 1 , x 2 , … , x n } X = \{x_1, x_2, \ldots, x_n\} X={x1,x2,…,xn},初始时每个数据点作为一个独立的簇。记每个数据点对应的簇为 C i = { x i } C_i = \{x_i\} Ci={xi}。
2. 距离度量 为了判断簇之间的相似度,首先需要定义簇之间的距离。对于任意两个簇 C i C_i Ci 和 C j C_j Cj,选择一种距离度量方法,常见的有:
- 单链接(Single Linkage): d ( C i , C j ) = min x ∈ C i , y ∈ C j d ( x , y ) d(C_i, C_j) = \min_{x \in C_i, y \in C_j} d(x, y) d(Ci,Cj)=x∈Ci,y∈Cjmind(x,y)
- 全链接(Complete Linkage): d ( C i , C j ) = max x ∈ C i , y ∈ C j d ( x , y ) d(C_i, C_j) = \max_{x \in C_i, y \in C_j} d(x, y) d(Ci,Cj)=x∈Ci,y∈Cjmaxd(x,y)
- 平均链接(Average Linkage): d ( C i , C j ) = 1 ∣ C i ∣ ⋅ ∣ C j ∣ ∑ x ∈ C i ∑ y ∈ C j d ( x , y ) d(C_i, C_j) = \frac{1}{|C_i| \cdot |C_j|} \sum_{x \in C_i} \sum_{y \in C_j} d(x, y) d(Ci,Cj)=∣Ci∣⋅∣Cj∣1x∈Ci∑y∈Cj∑d(x,y)
- Ward方法: d ( C i , C j ) = ∣ C i ∣ ⋅ ∣ C j ∣ ∣ C i ∣ + ∣ C j ∣ ⋅ ∥ μ i − μ j ∥ 2 d(C_i, C_j) = \sqrt{\frac{|C_i| \cdot |C_j|}{|C_i| + |C_j|} \cdot \|\mu_i - \mu_j\|^2} d(Ci,Cj)=∣Ci∣+∣Cj∣∣Ci∣⋅∣Cj∣⋅∥μi−μj∥2 其中, μ i \mu_i μi 和 μ j \mu_j μj 分别是簇 C i C_i Ci 和 C j C_j Cj 的质心(均值)。在聚类分析中, ∣ C k ∣ |C_k| ∣Ck∣ 表示簇 C k C_k Ck中的数据点的数量,即簇 C k C_k Ck的大小。
3. 合并过程
在每一步中,找到距离最小的两个簇 C a C_a Ca 和 C b C_b Cb,然后合并它们: C n e w = C a ∪ C b C_{new} = C_a \cup C_b Cnew=Ca∪Cb
更新簇的数量: k = k − 1 k = k - 1 k=k−1
4. 更新距离矩阵 合并后,需要更新距离矩阵。对于新产生的簇 C n e w C_{new} Cnew 和其他簇 C k C_k Ck 的距离可以根据选择的距离度量方式进行计算。例如:
- 对于单链接: d ( C n e w , C k ) = min ( d ( C a , C k ) , d ( C b , C k ) ) d(C_{new}, C_k) = \min(d(C_a, C_k), d(C_b, C_k)) d(Cnew,Ck)=min(d(Ca,Ck),d(Cb,Ck))
- 对于全链接: d ( C n e w , C k ) = max ( d ( C a , C k ) , d ( C b , C k ) ) d(C_{new}, C_k) = \max(d(C_a, C_k), d(C_b, C_k)) d(Cnew,Ck)=max(d(Ca,Ck),d(Cb,Ck))
- 对于平均链接: d ( C n e w , C k ) = ∣ C a ∣ ⋅ d ( C a , C k ) + ∣ C b ∣ ⋅ d ( C b , C k ) ∣ C a ∣ + ∣ C b ∣ d(C_{new}, C_k) = \frac{|C_a| \cdot d(C_a, C_k) + |C_b| \cdot d(C_b, C_k)}{|C_a| + |C_b|} d(Cnew,Ck)=∣Ca∣+∣Cb∣∣Ca∣⋅d(Ca,Ck)+∣Cb∣⋅d(Cb,Ck)
- 对于Ward方法: d ( C n e w , C k ) = ∣ C n e w ∣ ⋅ ∣ C k ∣ ∣ C n e w ∣ + ∣ C k ∣ ⋅ ∥ μ n e w − μ k ∥ 2 d(C_{new}, C_k) = \sqrt{\frac{|C_{new}| \cdot |C_k|}{|C_{new}| + |C_k|} \cdot \|\mu_{new} - \mu_k\|^2} d(Cnew,Ck)=∣Cnew∣+∣Ck∣∣Cnew∣⋅∣Ck∣⋅∥μnew−μk∥2
其中, μ n e w \mu_{new} μnew 是合并后新簇的质心。5. 终止条件
重复步骤3和步骤4,直到所有数据点合并为一个簇,或者达到预定的簇数量 k k k。
6. 结果表示
最终结果可以用树形图(dendrogram)表示,展示了所有簇的合并过程及其对应的距离。
通过以上的数学表达和步骤,可以较为清晰地理解凝聚型层次聚类的过程及其特征。
分裂型层次聚类(Divisive Hierarchical Clustering)
分裂型层次聚类(Divisive Hierarchical Clustering)是与凝聚型层次聚类相反的方法,它从一个整体簇开始,然后逐步将其分裂成更小的簇。以下是分裂型层次聚类的数学表达和过程描述:
1. 初始化
假设有 n n n 个数据点 X = { x 1 , x 2 , … , x n } X = \{x_1, x_2, \ldots, x_n\} X={x1,x2,…,xn},初始时所有数据点都被视为一个单一的簇:
C = { X } C = \{X\} C={X}2. 选择分裂簇
在每一步,选择一个簇 C k C_k Ck 进行分裂。通常选择具有最大内部离散度的簇,以确保分裂后的簇之间的差异最大。>##### 3. 距离度量
定义簇的离散度(内部距离),可以使用某种度量,例如簇的总方差:
D ( C k ) = ∑ x ∈ C k d ( x , μ k ) 2 D(C_k) = \sum_{x \in C_k} d(x, \mu_k)^2 D(Ck)=x∈Ck∑d(x,μk)2
其中 μ k \mu_k μk 是簇 C k C_k Ck 的质心, d ( x , μ k ) d(x, \mu_k) d(x,μk) 是数据点 x x x 到簇质心的距离。4. 分裂方法
选择一个适当的分裂方法(例如 K-means)。假设我们将簇 C k C_k Ck 分裂为两个子簇 C k 1 C_{k1} Ck1 和 C k 2 C_{k2} Ck2:
C k → C k 1 , C k 2 C_k \rightarrow C_{k1}, C_{k2} Ck→Ck1,Ck25. 更新簇的数量
增加新的簇数量:
m = m + 1 m = m + 1 m=m+16. 迭代过程
重复步骤 2 到 5,直到达到预定的簇数量 k k k 或者所有簇都无法再分裂为止。
7. 结果表示
最终结果可以用树形图(dendrogram)表示,展示了所有簇的分裂过程及其对应的离散度。
备注
在分裂型层次聚类中,选择分裂的方式和度量内部离散度的标准会显著影响聚类的结果。常用的分裂方法包括 K-means 算法、PCA 等。
手动实现
import numpy as np# 计算两个样本之间的欧氏距离
def euclidean_distance(a, b):return np.sqrt(np.sum((a - b) ** 2))# 计算簇之间的距离,这里使用最小距离法
def calculate_cluster_distance(cluster1, cluster2):min_distance = float('inf')for point1 in cluster1:for point2 in cluster2:distance = euclidean_distance(point1, point2)if distance < min_distance:min_distance = distancereturn min_distance# 初始化簇,每个样本作为一个簇
def initialize_clusters(points):return [[point] for point in points]# 找到距离最近的两个簇
def find_closest_clusters(clusters):min_distance = float('inf')pair = (None, None)for i in range(len(clusters)):for j in range(i + 1, len(clusters)):distance = calculate_cluster_distance(clusters[i], clusters[j])if distance < min_distance:min_distance = distancepair = (i, j)return pair# 合并两个簇
def merge_clusters(clusters, pair):i, j = pairmerged_cluster = clusters[i] + clusters[j]clusters.pop(j)clusters.pop(i)clusters.append(merged_cluster)return clusters# 凝聚型层次聚类
def agglomerative_clustering(points, distance_threshold):clusters = initialize_clusters(points)while len(clusters) > 1:closest_pair = find_closest_clusters(clusters)if calculate_cluster_distance(clusters[closest_pair[0]], clusters[closest_pair[1]]) > distance_threshold:breakclusters = merge_clusters(clusters, closest_pair)return clusters# 示例数据
points = np.array([[1, 2], [2, 2], [5, 8], [1, 3], [8, 8], [9, 10]])# 调用凝聚型层次聚类算法
clusters = agglomerative_clustering(points, distance_threshold=5)# 打印结果
for i, cluster in enumerate(clusters):print(f"Cluster {i+1}: {cluster}")
结果为:
代码分析
distance = euclidean_distance(point1, point2)
对于
points
列表中的每一个元素point
,将其放入一个新列表中,然后将这些新列表组成一个新的列表。agglomerative_clustering(points, distance_threshold=5)中distance_threshold
distance_threshold(距离阈值):在聚类分析中,这是用来决定两个簇是否应该被视为“接近”或“相似”的临界值。如果两个簇之间的距离小于或等于这个阈值,则通常认为这两个簇足够接近,可以考虑将它们合并;如果距离大于这个阈值,则认为它们是独立的,不应该合并。
代码为,如果计算得出的两个最近簇(clusters[closest_pair[0]]
和clusters[closest_pair[1]]
)之间的距离大于给定的距离阈值(distance_threshold
),那么执行if语句块中的代码:运行结束。