Python實現K-means程式碼詳解(新手上路)
阿新 • • 發佈:2019-01-04
#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