K-Means

本文详细介绍了K-均值聚类算法的工作原理及其实现过程,包括算法的优点、局限性及其在大规模数据集上的应用。此外还探讨了二分K-均值聚类算法,并提供了Python代码实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

K-均值聚类算法
    优点:容易实现,不足之处可能收敛到局部最小值,在大规模数据集上收敛较慢,适用于数值型数据。工作流程如下:
 创建k个点作为起始质心(经常是随机选择)
当任意一个点的簇分配结果发生改变时
    对数据集中的每个数据点
        对每个质心
              计算质心与数据点之间的距离
        将数据点分配到距其最近的簇

    对每一个簇,计算簇中所有点的均值并将均值作为质心

#-*- coding:utf-8 -*-
from numpy import *
def loadDataSet(fileName):
    dataMat=[]
    fr=open(fileName)
    for line in fr.readlines():
        curLine=line.strip().split('\t')
        fitLine=map(float,curLine)
        dataMat.append(fitLine)
    return dataMat
#计算两个向量的欧氏距离
def distEclud(vecA,vecB):
    return sqrt(sum(power(vecA-vecB,2)))
#给定数据集构建一个包含k个随机质心的集合
def randCent(dataSet,k):
    n=shape(dataSet)[1]
    centroids=mat(zeros((k,n)))
    #随机质心必须要在整个数据集的边界之内,通过找到每一维最小和最大值完成
    for j in range(n):
        minJ=min(dataSet[:,j])
        rangeJ=float(max(dataSet[:,j])-minJ)
        centroids[:,j]=minJ+rangeJ*random.rand(k,1)#生成0到1.0之间的随机数并通过取值范围和最小值确保随机点在数据边界之内
    return centroids
>>> import kmeans
>>> from numpy import *
>>> datMat=mat(kmeans.loadDataSet('E:/code/testSet.txt'))
>>> min(datMat[:,0])
matrix([[-5.379713]])
>>> min(datMat[:,1])
matrix([[-4.232586]])
>>> max(datMat[:,1])
matrix([[ 5.1904]])
>>> max(datMat[:,0])
matrix([[ 4.838138]])

>>> kmeans.randCent(datMat,2)
matrix([[ 1.58043495, -1.31447897],
        [ 1.70103927,  4.95529564]])

测试一下距离的计算方法:

>>> kmeans.distEclud(datMat[0],datMat[1])
5.184632816681332

    所支持的函数正常运行,准备实现K均值算法。创建k个质心,然后将每个点分配到最近的质心,在重新计算质心。重复数次,直到数据点的簇分配结果不会改变为止。

#数据集及簇的数目是必选参数,计算距离和创建初始质心的函数可选
def keans(dataSet,k,distMeas=distEclud,createCent=randCent):
    m=shape(dataSet)[0]#创建一个矩阵来存储每个点的簇分配结果
    clusterAssment=mat(zeros((m,2)))#一列记录簇索引值,一列存储误差
    centroids=createCent(dataSet,k)
    clusterChanged=True#标识变量,true则继续迭代
    #遍历所有数据找到距离每个点最近的质心,对每个点遍历所有质心并计算每个质心的距离来完成
    while clusterChanged:
        clusterChanged=False
        for i in range(m):
            minDist=inf;minIndex=-1
            for j in range(k):
                distJI=distMeas(centroids[j,:],dataSet[i,:])
                if distJI<minDist:
                    minDist=distJI;minIndex=j
            if clusterAssment[i,0]!=minIndex:clusterChanged=True
            clusterAssment[i,:]=minIndex,minDist**2
        print centroids
        #遍历并更新取值,通过数组过滤来获得给定簇的所有点,计算均值,axis=0表示沿矩阵列的方向进行均值计算
        for cent in range(k):
            ptsInClust=dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]
            centroids[cent,:]=mean(ptsInClust,axis=0)
    return centroids,clusterAssment
>>> reload(kmeans)
<module 'kmeans' from 'E:\python\kmeans.py'>
>>> datMat=mat(kmeans.loadDataSet('E:/code/testSet.txt'))
>>> myCenttroids,clustAssing=kmeans.keans(datMat,4)
[[-2.70314932  2.01452543]
 [ 0.89843689  2.61822779]
 [ 1.18644542 -3.90997013]
 [ 3.1300084  -2.7441036 ]]
[[-3.07195136  0.92565029]
 [ 2.24547378  2.92273278]
 [-2.00155638 -3.472942  ]
 [ 3.25624481 -2.728045  ]]
[[-2.54951105  2.75812458]
 [ 2.46383071  3.1198451 ]
 [-3.19984738 -2.96423548]
 [ 2.926737   -2.70147753]]
[[-2.46154315  2.78737555]
 [ 2.6265299   3.10868015]
 [-3.38237045 -2.9473363 ]
 [ 2.80293085 -2.7315146 ]]

二分K-均值算法:

 将所有点看成一个簇

当簇数目小于k时

    对于每一个簇

        计算总误差

        在给定的簇上面进行K-均值聚类(k=2)

         计算将该簇一分为二之后的总误差

    选择使得误差最小的那个簇进行划分操作

def biKmeans(dataSet,k,distMeas=distEclud):
    m=shape(dataSet)[0]
    clusterAssment=mat(zeros((m,2)))
    #创建一个初始簇,存储数据集中每个点的簇分配结果集平方误差
    centroid0=mean(dataSet,axis=0).tolist()[0]
    centList=[centroid0]
    #计算质心并保存,可以遍历数据集中所有点来计算每个点到质心的误差值
    for j in range(m):
        clusterAssment[j,1]=distMeas(mat(centroid0),dataSet[j,:])**2
    while (len(centList)<k):
        lowestSSE=inf#将最小SSE设置为无穷大
        #尝试划分每一簇
        for i in range(len(centList)):
            ptsInCurrCluster=dataSet[nonzero(clusterAssment[:,0].A!=i)[0],:]#小数据集
            centroidMat,splitClustAss=kMeans(ptsInCurrCluster,2,distMeas)#k-均值算法会生成两个质心,同时给出误差值
            sseSplit=sum(splitClustAss[:,1])
            sseNotSplit=sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])
            print "sseSplit,and not Split:",sseSplit,sseNotSplit
            if(sseSplit+sseNotSplit)<lowestSSE:
                bestCentToSplit=i
                bestNewCents=centroidMat
                bestClustAss=splitClustAss.copy()
                lowestSSE=sseSplit+sseNotSplit#将误差与剩余数据集误差之之和作为划分的误差
        bestClustAss[nonzero(bestClustAss[:,0].A==1)[0],0]=len(centList)
        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,:]#新的簇结果被更新
        centList.append(bestNewCents[1,:])
        clusterAssment[nonzero(clusterAssment[:,0].A==bestCentToSplit)[0],:]=bestClustAss
    return mat(centList),clusterAssment
>>> reload(kmeans)
<module 'kmeans' from 'E:\python\kmeans.py'>
>>> datMat3=mat(kmeans.loadDataSet('E:/code/testSet2.txt'))
>>> centList,myNewAssments=kmeans.biKmeans(datMat3,3)
[]

Traceback (most recent call last):
  File "<pyshell#40>", line 1, in <module>
    centList,myNewAssments=kmeans.biKmeans(datMat3,3)
  File "E:\python\kmeans.py", line 65, in biKmeans
    centroidMat,splitClustAss=kMeans(ptsInCurrCluster,2,distMeas)#k-均值算法会生成两个质心,同时给出误差值
  File "E:\python\kmeans.py", line 31, in kMeans
    centroids=createCent(dataSet,k)
  File "E:\python\kmeans.py", line 24, in randCent
    rangeJ=float(max(dataSet[:,j])-minJ)
ValueError: max() arg is an empty sequence

为什么出错呢?试了好几种方法,求大神指点,多谢!




<think>嗯,用户想了解k-means聚类算法的介绍及实现方法。首先,我需要回顾一下k-means的基本概念。记得它是一种无监督学习算法,用于将数据分成k个簇。步骤的话,应该是初始化质心,分配数据点到最近的质心,重新计算质心,然后重复直到收敛。对了,初始质心的选择可能影响结果,所以有k-means++这样的改进方法。 然后,用户可能还关心实现方法。得准备用Python或者Matlab的例子。不过用户提供的引用里有Python和Matlab的代码示例,可能需要参考一下。比如引用3和4提到了Python实现,而引用1是Matlab的。需要确定用户偏向哪种语言,但问题里没有明确说明,所以最好都给出或者选一种常见的,比如Python。 接下来,考虑用户可能的需求。他们可能需要步骤的详细解释,避免太技术化的术语,但又要准确。比如,初始质心的选择,迭代过程,收敛条件等。还要提到优缺点,比如对初始值敏感,适合凸数据集,可能不适用于非球形簇。 另外,引用里提到了优化方法,比如k-means++、Mini-batch、二分k-means,这些也应该包括在回答里,作为改进方向。用户的问题还可能涉及到应用场景,比如客户分群,市场营销,所以举例子的时候可以提到这些。 需要检查LaTeX格式是否正确,确保数学表达式用$...$,比如欧氏距离公式$d(x, y) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2}$。独立公式用$$...$$,比如目标函数SSE。还要注意引用标识的位置,例如在提到k-means++时引用[^2]。 可能的问题点:是否覆盖了所有关键点,步骤是否清晰,代码示例是否正确,引用是否正确关联。比如,引用4提到二分k-means,应该在优化部分提到。还要注意避免错误,比如k-means的停止条件通常是质心不再变化或迭代次数,需要准确描述。 最后,生成相关问题要考虑用户可能的后续疑问,比如如何选择k值,算法的时间复杂度,与其他聚类算法的比较等。确保问题相关且有引导性。</think>### K-means聚类算法介绍及实现方法 K-means聚类算法是一种经典的无监督学习方法,通过迭代将数据集划分为$k$个簇,使得同一簇内的样本相似度高,不同簇间差异显著[^3]。 #### 一、算法原理 1. **初始化**:随机选择$k$个初始质心(每个簇的中心点)。 2. **分配样本**:计算每个样本到所有质心的距离(如欧氏距离$d(x, y) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2}$),将其分配到最近的质心对应簇。 3. **更新质心**:重新计算每个簇的质心(即簇内样本均值)。 4. **迭代**:重复步骤2-3,直到质心变化小于阈值或达到最大迭代次数。 目标是最小化**簇内平方误差和(SSE)**: $$SSE = \sum_{i=1}^k \sum_{x \in C_i} \|x - \mu_i\|^2$$ 其中$\mu_i$是第$i$个簇的质心,$C_i$为第$i$个簇的样本集合[^4]。 #### 二、Python实现示例 ```python import numpy as np from sklearn.cluster import KMeans # 生成示例数据 X = np.array([[1, 2], [1, 4], [1, 0], [4, 2], [4, 4], [4, 0]]) # 使用K-means算法(k=2) kmeans = KMeans(n_clusters=2, init='k-means++', max_iter=300) kmeans.fit(X) print("质心坐标:", kmeans.cluster_centers_) print("样本所属簇:", kmeans.labels_) ``` #### 三、优化方法 - **K-means++**:优化初始质心选择,降低陷入局部最优的风险[^2]。 - **二分K-means**:通过逐步分裂簇提升稳定性。 - **Mini-batch K-means**:适用于大规模数据,每次迭代仅用部分样本加速计算。 #### 四、应用场景 1. 客户分群(如市场营销策略制定) 2. 图像压缩(颜色量化) 3. 异常检测(稀疏簇可能包含异常点) #### 五、优缺点 - **优点**:简单高效,时间复杂度为$O(n \cdot k \cdot t)$($n$样本数,$k$簇数,$t$迭代次数)。 - **缺点**:需预设$k$值;对初始质心敏感;仅适用于凸形簇。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值