Python实现K-means代码详解(新手上路)

#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]      #shape(dataSet)获得数据集的形状,       即数据集是几行几列的,然后取下标为1的元素
20     centroids = mat(zeros((k,n)))    #初始化一个k行n列的二维数组,数组初始值全部为0,然后用mat函数将其转化为矩阵
21     for j in range(n):
22         minJ = min(dataSet[:,j])     #[:,j]:逗号前部分表示取dataSet数据集所有行,j表示取第j列。本句含义:依次取dataSet数据集第j列最小值,j从0到n。参考文献:https://blog.csdn.net/github_36669230/article/details/78038756
23         rangeJ = float(max(array(dataSet)[:,j]) - minJ)       #max(array(dataSet)[:,j]):取数据集中第j列的最大值。本句含义:用第j列最大值减去最小值,获得第j列元素的取值范围
24         centroids[:,j] = minJ + rangeJ * random.rand(k,1)    #numpy.random.rand() 

官方文档中给出的用法是:numpy.random.rand(d0,d1,…dn) 
以给定的形状创建一个数组,并在数组中加入在[0,1]之间均匀分布的随机样本。例:a=np.random.rand(2,3),表示创建一个形状为二维三列的数组,数组元素在0到1之间均匀分布。
    25     return centroids
    26     
    27 def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
    #将函数distEclud和randCent作为参数传进来,可以更好的封装kMeans函数
    28     m = shape(dataSet)[0]  #获得数据集的形状后,取第0列数据,即获得数据集的行数
    29     clusterAssment = mat(zeros((m,2)))    # clusterAssment是一个m行2列的矩阵,第一列存放每个样本所属聚类中心的下标,第二列存放该样本与该聚类中心的距离
    30                                      
    31     centroids = createCent(dataSet, k)
    32     clusterChanged = True
    33     while clusterChanged:
    34         clusterChanged = False
    #下面两个for循环计算每一个样本到每一个聚类中心的距离
    35         for i in range(m):   #取每一个样本
    36             minDist = inf     #inf表示无穷大,-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):     #重新计算聚类中心,cent从0遍历到k
    47             ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]          
                     #clusterAssment[:,0]:取得clusterAssment中第0列元
                     素。
                     #clusterAssment[:,0].A:转置成一个1行m列的行矩阵
                     #clusterAssment[:,0].A==cent :将行矩阵中每一个元素与
                     cent进行比较,得到一个1行m列、元素取值为True和false
                     的矩阵,元素为true表示该样本是第cent个聚类中心的点
                     #nonzero(clusterAssment[:,0].A==cent)[0]:获得元素值为
                     True的元素下标,这些下标集合即为所有属于cent类的样 
                      本下标
                     #整句含义:取得数据集中属于第cent个簇的样本集
    48             centroids[cent,:] = mean(ptsInClust, axis=0)
                      #对ptsInClust的每一列计算平均值,生成新的聚类中心
     				  #axis=0:进行列运算
    				  #centroids[cent,:]:第cent行
    49     return centroids, clusterAssment
    50     
    51 def show(dataSet, k, centroids, clusterAssment):
    52     from matplotlib import pyplot as plt  
    53     numSamples, dim = dataSet.shape  #dataSet.shape返回两个
    													#值,分别赋给numSamples和dim
    54     mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']  #样本集的显
                          																	 #示样式
    55     for i in xrange(numSamples):  #xrange一次加载一个数,range
    								#一次加载完所有数。当数据范围较大时,range
    								#一次性加载完所有数据,效率较慢。
    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()        #python代码按照顺序从头到尾执行,不执行def开头的函数,def函数只有被调用时才执行。本句意思是:判断正在执行的程序是否有主函数,若有,则不执行第71行语句;若没有,则调用main函数

参考文献:http://www.cnblogs.com/MrLJC/p/4127553.html

猜你喜欢

转载自blog.csdn.net/u011208984/article/details/85376671