K-means的改进

前言

k-means算法是数据挖掘十大经典算法之一,已出现了很多的改进或改良算法。例如

  • 1、对k的选择可以先用一些算法,分析数据的分布,如重心和密度等,然后选择合适的k。
  • 2、有人提出了二分k均值(bisecting k-means)算法,它对初始的k个质心的选择就不太敏感。
  • 3、基于图划分的谱聚类算法,能够很好地解决非凸数据的聚类。

一、Canopy算法配合初始聚类

1.1、算法原理

  • 选择质心,T1圆内的点归为本簇,T1到T2范围内的点属于可疑点(黑色的点), T2外的点为簇外点(绿色的点)
  • 从簇外点中选择质心,然后根据T1,T2划分
    • T1范围内的可疑点,划到本簇,
    • 直到所有的簇外点划分完成
      在这里插入图片描述
      划分完成, 对于较小的簇将其去掉, 此时的K值可以作为K-means的初始K值
      在这里插入图片描述

1.2、Canopy的优缺点

1.2.1、优点

  • 1、 Kmeans对噪声抗干扰较弱,通过Canopy 对比,将较小的NumPoint的Cluster直接去掉有利于抗干扰。
  • 2、Canopy选择出来的每个Canopy的centerPoint作为K会更精确。
  • 3、只是针对每个Canopy的内做Kmeans聚类, 减少相似计算的数量。

1.2.2、缺点(问题)

  这和需要设置初始条件的算法都有的通病,就是初始条件的选取

算法中 T1、T2的确定问题

二、K-means++

P = D ( x ) 2 ∑ x ∈ X D ( x ) 2 P= \frac{D(x)^2}{\sum_{x \in X}D(x)^2} P=xXD(x)2D(x)2

参考:https://www.cnblogs.com/wang2825/articles/8696830.html

其实这个算法也只是对初始点的选择有改进而已,其他步骤都一样。初始质心选取的基本思路就是,初始的聚类中心之间的相互距离要尽可能的远。

算法描述如下:

  • 步骤一:随机选取一个样本作为第一个聚类中心 c1;

  • 步骤二:

    • 计算每个样本与当前已有类聚中心最短距离(即与最近一个聚类中心的距离),用 D(x)表示;这个值越大,表示被选取作为聚类中心的概率较大;
    • 最后,用轮盘法选出下一个聚类中心;
  • 步骤三:重复步骤二,知道选出 k 个聚类中心。

  • 选出初始点后,就继续使用标准的 k-means 算法了

三、二分K-means

3.1、算法思路

  • 所有点作为一个簇
  • 将该簇一分为二
  • 选择能最大限度降低聚类代价函数(也就是误差平方和SSE)的簇 划分为两个簇。
  • 以此进行下去,直到簇的数目等于用户给定的数目k为止。

在这里插入图片描述

3.2、算法实现

#二分kmeans        
def biKmeans(dataSet, k, distMeas=distEclud):
    m = shape(dataSet)[0]
    clusterAssment = mat(zeros((m,2)))
    #所有样本看成一个簇,求均值
    centroid0 = mean(dataSet, axis=0).tolist()[0]#axis=0按列,matrix->list
    centList =[centroid0] #create a list with one centroid
    for j in range(m): #计算初始总误差SSE
        clusterAssment[j,1] = distMeas(mat(centroid0), dataSet[j,:])**2
    #当簇数<k时
    while (len(centList) < k):
        lowestSSE = inf  #初始化SSE
        #对每个簇
        for i in range(len(centList)):
            #获取当前簇cluster=i内的数据
            ptsInCurrCluster = dataSet[nonzero(clusterAssment[:,0].A==i)[0],:]
            
            #对cluster=i的簇进行kmeans划分,k=2
            centroidMat, splitClustAss = kMeans(ptsInCurrCluster, 2, distMeas)
            
            #cluster=i的簇被划分为两个子簇后的SSE
            sseSplit = sum(splitClustAss[:,1])
            
            #除了cluster=i的簇,其他簇的SSE
            sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])
            print("sseSplit, and notSplit: ",sseSplit,sseNotSplit)
            
            #找最佳的划分簇,使得划分后 总SSE=sseSplit + sseNotSplit最小
            if (sseSplit + sseNotSplit) < lowestSSE: 
                bestCentToSplit = i    
                bestNewCents = centroidMat #被划分簇的两个新中心
                bestClustAss = splitClustAss.copy() #被划分簇的聚类结果0,1 ,及簇内SSE
                lowestSSE = sseSplit + sseNotSplit
                
        #将最佳被划分簇的聚类结果为1的类别,更换类别为len(centList)
        bestClustAss[nonzero(bestClustAss[:,0].A == 1)[0],0] = len(centList)  
        
        #将最佳被划分簇的聚类结果为0的类别,更换类别为bestCentToSplit
        bestClustAss[nonzero(bestClustAss[:,0].A == 0)[0],0] = bestCentToSplit
        print('the bestCentToSplit is: ',bestCentToSplit)
        print('the len of bestClustAss is: ', len(bestClustAss))
        
        #将被划分簇的一个中心,替换为划分后的两个中心
        centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0] 
        centList.append(bestNewCents[1,:].tolist()[0])
        
        #更新整体的聚类效果clusterAssment(类别,SSE)
        clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:]= bestClustAss
        #kMeans.datashow(dataSet,len(centList),mat(centlist),clusterAssment)   
    return mat(centList), clusterAssment

四、Kernel k-means

线性可分与线性不可分, 通过核函数将数据提升到高维,是的在低维线性不可分的数据,变成高维的线性可分。

4.1、通过映射关系,将数据映射到高维空间,然后在高维可以线性可用

注意:核函数是用来计算 映射后的内积,

在这里插入图片描述
  将每个样本进行一个投射到高维空间的处理,然后再将处理后的数据使用普通的k-means算法思想进行聚类。

五、 k-medoids(k-中心聚类算法)

5.1、原理

K-medoids和K-means是有区别的,不一样的地方在于中心点的选取

  • K-means中,将中心点取为当前cluster中所有数据点的平均值,对异常点很敏感!

  • K-medoids法选取的中心点为当前cluster中存在的一点,准则函数是当前cluster中所有其他点到该中心点的距离之和最小,这就在一定程度上削弱了异常值的影响,但缺点是计算较为复杂,耗费的计算机时间比K-means多。

K-medoids使用绝对差值和(Sum of Absolute Differences,SAD)的度量来衡量聚类结果的优劣,在n维空间中,计算SAD的公式如下所示:
在这里插入图片描述

5.1、算法流程

  • ( 1 )总体n个样本点中任意选取k个点作为medoids
  • ( 2 )按照与medoids最近的原则,将剩余的n-k个点分配到当前最佳的medoids代表的类中
  • ( 3 )对于第i个类中除对应medoids点外的所有其他点,按顺序计算当其为新的medoids时,代价函数的值,遍历所有可能,选取代价函数最小时对应的点作为新的medoids
  • ( 4 )重复2-3的过程,直到所有的medoids点不再发生变化或已达到设定的最大迭代次数
  • ( 5 )产出最终确定的k个类

5.2、K-Menas与K-Medoids的对比

在这里插入图片描述

六、ISODATA(迭代自组织数据分析算法)

  在K-均值算法的基础上,对分类过程增加了“合并”和“分裂”两个操作,并通过设定参数来控制这两个操作的一种聚类算法。

  • “合并”:当聚类结果某一类中样本数太少,或两个类间的距离太近
  • “分裂”:当聚类结果中某一类的类内方差太大,将该类进行分裂

七、Mini Batch K-Means(适合大数据的聚类算法)

  大数据量是什么量级?通过当样本量大于1万做聚类时,就需要考虑选用Mini Batch K-Means算法。
  Mini Batch KMeans使用了Mini Batch(分批处理)的方法对数据点之间的距离进行计算。 Mini Batch 计算过程中不必使用所有的数据样本,而是从不同类别的样本中抽取一部分样本来代表 各自类型进行计算。由于计算样本量少,所以会相应的减少运行时间,但另一方面抽样也必然会带 来准确度的下降

小结

在这里插入图片描述

### 改进的 K-means 聚类算法实现与应用 #### 二分 K-means 算法概述 为了克服传统 K-means 易受初始质心位置影响并可能陷入局部最优解的问题,提出了二分 K-means 算法。此方法通过逐步分裂现有簇来构建最终的聚类结构,在每次迭代过程中选择使误差平方和(SSE)减少最多的簇进行分割[^1]。 #### Python 实现示例 下面是一个简单的Python代码片段用于展示如何利用 `sklearn` 库中的工具实现二分 K-means: ```python from sklearn.cluster import KMeans import numpy as np def bisecting_kmeans(data, k_max): clusters = [[i for i in range(len(data))]] while len(clusters) < k_max: best_sse_reduction = -np.inf best_split_index = None for idx, cluster_indices in enumerate(clusters): X_cluster = data[cluster_indices] if len(X_cluster) <= 1: continue km_2 = KMeans(n_clusters=2).fit(X_cluster) sse_before = sum(np.min(cdist(X_cluster, [km_2.cluster_centers_[0]], 'euclidean')**2)) sse_after = sum(km_2.inertia_) reduction = (sse_before - sse_after) if reduction > best_sse_reduction: best_sse_reduction = reduction best_split_index = idx old_cluster = clusters.pop(best_split_index) new_km = KMeans(n_clusters=2).fit(data[old_cluster]) labels = new_km.labels_ clusters.append([old_cluster[i] for i in range(len(old_cluster)) if labels[i]==0]) clusters.append([old_cluster[i] for i in range(len(old_cluster)) if labels[i]==1]) return clusters ``` 上述函数实现了基本的二分 K-means 流程,并返回包含各个样本所属簇索引列表的结果集合。注意这里假设输入的数据集已经进行了预处理(如标准化),并且可以直接应用于距离计算操作中。 #### 应用场景探讨 改进后的 K-means 版本特别适用于那些对初始化敏感的应用领域,比如图像压缩、客户细分以及文档分类等任务。由于其能够更稳定地收敛到全局较优解,因此可以在这些场合提供更加可靠且高质量的聚类结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值