K-means聚类算法
来源:互联网 发布:python 人工智能 开发 编辑:程序博客网 时间:2024/05/16 06:49
聚类:是一种无监督学习,它将相似的对象归到同一个簇中。
聚类方法几乎可以应用于所有对象,簇内的对象越相似,聚类的效果越好。聚类分析试图将相似对象归入同一簇,将不相似对象归到不同簇。相似这一概念取决于所选择的相似度计算方法。
聚类和分类的最大区别:分类的目标事先已知,而聚类则不一样。
我们即将要介绍的K均值算法就是一种聚类算法,之所以称之为K--均值,是因为他可以发现k个不同的簇,且每个簇的中心采用簇中所含值的均值计算而成。
K-均值是发现给定数据集的k个簇的算法。簇个数k是用户给定的,每一个簇通过其质心(centroid),即簇中所有点的中心来描述。
K-均值算法思想:首先,随机确定k个初始点作为质心。然后将数据集中的每个点分配到一个簇中,具体来讲,为每个点找距其最近的质心,并将其分配给该质心所对应的簇。完成这一步后,每个簇的质心更新为该簇所有点的平均值。
K--均值算法的代码实现:
1、K-均值聚类支持函数
# -*- coding: cp936 -*-from numpy import *#K-均值聚类支持函数def loadDataSet(fileName): dataMat = [] fr = open(fileName) for line in fr.readlines(): curLine = line.strip().split('\t') print(curLine) fltLine = map(float,curLine)#将curLine中的数据转成float print(fltLine) dataMat.append(fltLine) 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)))#k行n列的mat for j in range(n): minJ = min(dataSet[:,j]) rangeJ = float(max(dataSet[:,j]) - minJ) centroids[:,j] = minJ + rangeJ * random.rand(k,1) return centroids
代码测试:
datMat = mat(Kmeans.loadDataSet('KtestSet.txt'))
myCentroids, clustAssing = Kmeans.kMeans(datMat,4)[[ 2.9332215 2.22861698] [ 1.69268674 -4.10293577] [ 0.91368859 -2.42097458] [ 3.3841354 1.52146566]][[ 0.16309271 3.17495486] [ 2.845833 -3.38251675] [-2.45947514 -2.32683068] [ 4.1436012 -0.2075728 ]][[-0.23940082 3.198336 ] [ 2.60401887 -3.15076575] [-3.35883359 -2.57409073] [ 3.53791189 0.64902844]][[-0.87618583 3.19731776] [ 2.54173689 -3.11892933] [-3.4967025 -2.70989515] [ 3.17716292 1.68927015]][[-1.94392522 2.96291883] [ 2.56468005 -2.8885874 ] [-3.53973889 -2.89384326] [ 2.91014783 2.71954072]][[-2.46154315 2.78737555] [ 2.65077367 -2.79019029] [-3.53973889 -2.89384326] [ 2.6265299 3.10868015]]
2、K-均值聚类算法
#K-均值聚类算法def kMeans(dataSet,k,distMeas=distEclud, createCent=randCent): m = shape(dataSet)[0] clusterAssment = mat(zeros((m,2))) centroids = createCent(dataSet, k) clusterChanged = 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 <span style="color:#ff0000;">#clusterAssment包含两列:一列记录簇索引值,第二列存储误差</span> print(centroids) for cent in range(k): ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]<span style="color:#ff0000;">#将clusterAssment中第一列中等于cent的索引<span style="white-space:pre"></span> #对应的dataSet中数提取出来,放到ptsInClust中</span> #print(ptsInClust,"xiaobiao",nonzero(clusterAssment[:,0].A==cent)) #print(nonzero(clusterAssment[:,0].A==cent)[0]) centroids[cent,:] = mean(ptsInClust, axis=0)<span style="color:#ff0000;">#将这些点的平均点作为质心</span> return centroids, clusterAssment
问题:上面的方法有一个问题,由于k是我们自己定义的,
问题1、那么用户如何知道才能知道k的选择是否正确呢?
问题2、我们怎么样才能知道生成的簇比较好呢?
对于问题1:我们可以用下面的二分k-均值聚类算法来解决。
对于问题2:我们用于度量聚类效果的指标是SSE(Sum of Squared Error,误差平方和)。
例如:对于clusterAssment矩阵的第一列之和。SSE值越小表示数据点越接近于他们的质心,聚类效果也越好。
我们可以对上面的方法进行改进,以此来降低SSE的大小。那么如何改进呢?方法1:增加簇的个数肯定可以降低SSE的值,但是这违背了聚类的目标。聚类的目标是在保持簇不变的情况下提高簇的质量。
方法2:将具有最大SSE的簇生成两簇,但是为了保持总簇不变,可以将某两簇进行合并。合并最近的质心或者合并两个使得SSE增幅最小的质心(合并两个簇然后计算总的SSE值,所有的两个簇都得计算,知道找出合并最佳的簇)。
下面要说的二分k-均值聚类算法就用到了上述划分技术:
思想:该算法首先将所有点作为一个簇,然后将该簇一分为二。之后选择其中一个粗继续进行划分,选择哪一个簇进行划分取决于对其划分是否可以最大程度降低SSE的值。
上述基于SSE的划分过程不断重复,直到得到用户指定的簇数目为止。
#二分K-均值聚类算法def biKmeans(dataSet, k, distMeas=distEclud): m = shape(dataSet)[0] clusterAssment = mat(zeros((m,2))) centroid0 = mean(dataSet, axis=0).tolist()[0] centList = [centroid0]<span style="color:#ff0000;">#用一个列表来保留所有的质心</span> for j in range(m):<span style="color:#ff0000;">#计算每个点到质心的误差值,后面会用到这些误差值.</span> clusterAssment[j,1] = distMeas(mat(centroid0),dataSet[j,:])**2 while (len(centList) < k):<span style="color:#ff0000;">#该循环会不停的对簇进行划分,直到得到想要的簇数目k为止</span> lowestSSE = inf for i in range(len(centList)): ptsInCurrCluster = dataSet[nonzero(clusterAssment[:,0].A==i)[0],:]<span style="color:#ff0000;">#第i行的所有数据</span> centroidMat, splitClustAss = kMeans(ptsInCurrCluster,2,distMeas)<span style="color:#ff0000;">#返回所有类的质心和点分配的结果</span> sseSplit = sum(splitClustAss[:,1])<span style="color:#ff0000;">#SSE总和</span> sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1])<span style="color:#ff0000;">#除i以外的所有的SSE的总和</span> print("sseSplit, and notSplit:",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,:].tolist()[0]#replace a centroid with two best centroids centList.append(bestNewCents[1,:].tolist()[0]) clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:]=bestClustAss#将误差小的放到一个clusterAssment中,接着分,直到达while到要求 return mat(centList),clusterAssment
测试结果:
>>>myCentroids, clustAssing = Kmeans.biKmeans(datMat,4)>>>myCentroidsmatrix([[-3.38237045, -2.9473363 ], [-2.46154315, 2.78737555], [ 2.80293085, -2.7315146 ], [ 2.6265299 , 3.10868015]])
- k-means聚类算法
- k-means聚类算法
- K-means聚类算法
- K-means聚类算法
- K-means聚类算法
- K-means聚类算法
- K-means聚类算法
- K-means聚类算法
- K-MEANS聚类算法
- k-means聚类算法
- K-means聚类算法
- 聚类算法 K-means
- K-means聚类算法
- K-means聚类算法
- K-means聚类算法
- 聚类算法:K-means
- K-means聚类算法
- K-means聚类算法
- 怎么样才算作弊搜索引擎
- Android L liblog
- 二分法+快速幂POJ 3233
- Android ListView那些事
- 最短路径之 floyd (适用于 多点距离)
- K-means聚类算法
- 控件CCtrlList的虚拟列表使用方法--详解
- VS2010/MFC入门编程二十(radio botton 的使用)
- 百度指数邀请码有没有?
- 快速幂POJ 1061
- 如果音乐网站因为版权问题而被关闭,那FLASH站点该怎么办?
- Ubuntu 鼠标一直闪动的问题解决
- 关于程序性能优化基础的一些个人总结
- 黑马程序员_内部类只能使用final变量深究