二分K-Means(Bisecting K-Means)是一种改进的聚类算法,它是K-Means算法的一种变体。

与传统的K-Means算法一次性生成K个聚类不同,二分K-Means通过递归将一个聚类分裂成两个,直到达到所需的聚类数目。

二分K-Means算法流程:

  1. 初始化:将所有数据点视为一个簇
  2. 分裂:从当前的簇中选择一个簇进行分裂。选择的标准通常是选择那些分裂后可以最大程度减少误差平方和(SSE)的簇。
  3. 应用K-Means:对选定的簇应用标准的K-Means算法,将其分成两个簇。
  4. 评估:检查是否达到了所需的聚类数目。如果没有,返回步骤2;如果达到了,算法结束。

涉及到的公式:

在二分K-Means中,最重要的公式是计算误差平方和(SSE),它用于决定哪个簇应该被分裂以及评估聚类的效果。SSE的公式如下:

二分K-Means(Bisecting K-Means)_机器学习

这里:

  • 二分K-Means(Bisecting K-Means)_kmeans_02聚类的数量;
  • 二分K-Means(Bisecting K-Means)_算法_03 是第 二分K-Means(Bisecting K-Means)_聚类_04聚类中的所有数据点;
  • 二分K-Means(Bisecting K-Means)_机器学习_05 是聚类 二分K-Means(Bisecting K-Means)_算法_03 中的某个数据点;
  • 二分K-Means(Bisecting K-Means)_聚类_07 是聚类 二分K-Means(Bisecting K-Means)_算法_03质心,计算方式为 二分K-Means(Bisecting K-Means)_初始化_09,其中 二分K-Means(Bisecting K-Means)_初始化_10 表示聚类 二分K-Means(Bisecting K-Means)_算法_03数据点的数量。

对公式中每个字符的解释:

  • 二分K-Means(Bisecting K-Means)_初始化_12:求和符号,表示对一系列项进行累加。
  • 二分K-Means(Bisecting K-Means)_聚类_04:聚类的索引。
  • 二分K-Means(Bisecting K-Means)_kmeans_02:总的聚类数目。
  • 二分K-Means(Bisecting K-Means)_机器学习_05:数据集中的一点。
  • 二分K-Means(Bisecting K-Means)_算法_03:第二分K-Means(Bisecting K-Means)_聚类_04个聚类的所有数据点组成的集合。
  • 二分K-Means(Bisecting K-Means)_聚类_07:第二分K-Means(Bisecting K-Means)_聚类_04个聚类的质心。
  • 二分K-Means(Bisecting K-Means)_kmeans_20:数据点二分K-Means(Bisecting K-Means)_机器学习_05与质心二分K-Means(Bisecting K-Means)_聚类_07之间的欧氏距离的平方。
  • 二分K-Means(Bisecting K-Means)_初始化_10:聚类二分K-Means(Bisecting K-Means)_算法_03中数据点的数量。

二分K-Means的目标是通过最小化SSE来获得更加紧凑和分离良好的聚类。

python代码

# 导入所需的库
from sklearn.cluster import KMeans
import numpy as np

# 定义数据点,这是一个二维数组,其中每个子数组代表一个数据点的坐标
data_points = np.array([[1, 2], [1.5, 1.8], [5, 8], [8, 8], [1, 0.6], [9, 11]])

# 定义二分K-Means算法的函数
def bisecting_kmeans(data, k):
    # 初始化,将所有数据点视为一个簇
    clusters = [data]
    
    # 当前簇的数量小于目标簇的数量时,继续循环
    while len(clusters) < k:
        # 初始化最大SSE为0,用于记录当前找到的最大SSE值
        max_sse = 0
        # 初始化要分裂的簇的索引为0
        index_to_split = 0
        # 遍历当前的所有簇
        for i, cluster in enumerate(clusters):
            # 对当前簇使用KMeans算法,将其分为两个簇
            kmeans = KMeans(n_clusters=2).fit(cluster)
            # 计算SSE,即簇内所有点到其所属簇质心距离的平方和
            # 使用np.linalg.norm计算每个点到最近质心的欧氏距离,然后平方求和
            sse = np.sum(np.linalg.norm(cluster - kmeans.cluster_centers_[kmeans.labels_], axis=1) ** 2)
            # 如果当前簇的SSE大于已知的最大SSE,则更新最大SSE和要分裂的簇的索引
            if sse > max_sse:
                max_sse = sse
                index_to_split = i
        
        # 根据找到的具有最大SSE的簇,使用KMeans算法将其分为两个簇
        split_cluster = clusters.pop(index_to_split)
        kmeans = KMeans(n_clusters=2).fit(split_cluster)
        
        # 将分裂后的簇按标签排序后分割成两个簇
        labels_sorted = np.argsort(kmeans.labels_)
        # 使用切片操作,根据标签排序后的结果,将split_cluster分为cluster1和cluster2
        cluster1 = split_cluster[labels_sorted[:len(labels_sorted)//2]]
        cluster2 = split_cluster[labels_sorted[len(labels_sorted)//2:]]
        
        # 将新生成的两个簇添加到clusters列表中
        clusters.append(cluster1)
        clusters.append(cluster2)
    
    # 当达到指定的簇数k时,返回当前的簇列表
    return clusters

# 设置聚类的数量
k = 2

# 调用bisecting_kmeans函数,传入数据点和聚类数量
clusters = bisecting_kmeans(data_points, k)

# 输出最终的聚类结果
for i, cluster in enumerate(clusters):
    print(f"Cluster {i+1}:")
    print(cluster)