1. 程式人生 > >Python實現K-means程式碼詳解(新手上路)

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