K-means算法

k-means算法属于无监督学习,没有已知的标签

k均值是发现给定数据集的K个簇的算法。

每个簇通过其质心来描述。

k均值算法的工作流程如下,

首先,给定随机的K个初始质心,然后将数据集中的每个点分配到一个簇中,过程是为每个点寻找最近的质心,并将其分配给该质心所对应的簇;

然后为每个簇更新质心,质心为所有点的平均值。

其伪代码如下:

创建k个点作为初始质心

当任意一个点的簇分配结果发生改变时

  对数据集中的每个点

    对每个质心  

      计算质心和该点的距离

    将该点分配到最近质心的簇

  对每一个簇,计算均值,更新质心。

 

 

重点是:1.随机   2.按距分配   3.均值更新

随机性往往使结果并不好,所以产生了后处理以及新的变形二分k-均值算法。

后处理

设置一个判断簇的好坏的标准,使用SSE(误差平方和)来判断。

后处理可以采用,将具有最大SSE的簇划分成两个簇,在这个大簇中采用k-均值;然后再把某两个簇合并,保持总数不变。合并的依据是,合并最近的质心或者合并两个使得SSE增幅最小的质心。

二分K均值算法

该算法首先将所有点作为一个簇,然后将该簇再一分为二,之后选择其中一个再进行划分,选择的依据是划分之后是否可以最大程度降低SSE的值。

这种基于SSE的划分过程不断重复,直到符合用户的簇数目。

伪代码如下:

一个整簇

当簇数目小于K时

  对每个簇

    计算总误差

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

    计算划分后的总误差

  选择误差小的那个簇进行划分

   

下面是一个简单的Kmeans的代码例子: 

 

 1 #coding=utf-8
 2 from numpy import *
 3 
 4 def loadDataSet(fileName):
 5     dataMat = []
 6     fr = open(fileName)
 7     for line in fr.readlines():
 8         curLine = line.strip().split('\t')
 9         fltLine = map(float, curLine)
10         dataMat.append(fltLine)
11     return dataMat
12     
13 #计算两个向量的距离,用的是欧几里得距离
14 def distEclud(vecA, vecB):
15     return sqrt(sum(power(vecA - vecB, 2)))
16 
17 #随机生成初始的质心(ng的课说的初始方式是随机选K个点)    
18 def randCent(dataSet, k):
19     n = shape(dataSet)[1]
20     centroids = mat(zeros((k,n)))
21     for j in range(n):
22         minJ = min(dataSet[:,j])
23         rangeJ = float(max(array(dataSet)[:,j]) - minJ)
24         centroids[:,j] = minJ + rangeJ * random.rand(k,1)
25     return centroids
26     
27 def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
28     m = shape(dataSet)[0]
29     clusterAssment = mat(zeros((m,2)))#create mat to assign data points 
30                                       #to a centroid, also holds SE of each point
31     centroids = createCent(dataSet, k)
32     clusterChanged = True
33     while clusterChanged:
34         clusterChanged = False
35         for i in range(m):#for each data point assign it to the closest centroid
36             minDist = inf
37             minIndex = -1
38             for j in range(k):
39                 distJI = distMeas(centroids[j,:],dataSet[i,:])
40                 if distJI < minDist:
41                     minDist = distJI; minIndex = j
42             if clusterAssment[i,0] != minIndex: 
43                 clusterChanged = True
44             clusterAssment[i,:] = minIndex,minDist**2
45         print centroids
46         for cent in range(k):#recalculate centroids
47             ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]#get all the point in this cluster
48             centroids[cent,:] = mean(ptsInClust, axis=0) #assign centroid to mean 
49     return centroids, clusterAssment
50     
51 def show(dataSet, k, centroids, clusterAssment):
52     from matplotlib import pyplot as plt  
53     numSamples, dim = dataSet.shape  
54     mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']  
55     for i in xrange(numSamples):  
56         markIndex = int(clusterAssment[i, 0])  
57         plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex])  
58     mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb']  
59     for i in range(k):  
60         plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 12)  
61     plt.show()
62       
63 def main():
64     dataMat = mat(loadDataSet('testSet.txt'))
65     myCentroids, clustAssing= kMeans(dataMat,4)
66     print myCentroids
67     show(dataMat, 4, myCentroids, clustAssing)  
68     
69     
70 if __name__ == '__main__':
71     main()

 

posted @ 2019-02-26 20:16  you-wh  阅读(524)  评论(0编辑  收藏  举报
Fork me on GitHub