python3對k-mean演算法的理解(轉)
阿新 • • 發佈:2018-12-18
1.隨機選取k個質心(k值取決於你想聚成幾類)
random.sample(dataSet, k) k你是想聚類的個數 dataset是資料集合 是陣列
2.dataSet 取出一條資料 然後分別與centroidList中的k的值進行歐氏距離的計算比較與哪個距離最短,儲存到對應的分類下
3.第一次分類後,計算均方誤差,是否大於0.001,如果不是,則將第一次的簇分類分別計算均值方差,分別成為新的中心
4.繼續迭代,判斷新舊質心是否相同,如果相同就代表已經聚類成功,如果沒有就迴圈2-3直到相同
寫了點自己理解
import numpy import random import codecs import copy import re import matplotlib.pyplot as plt def calcuDistance(vec1, vec2): # 計算向量vec1和向量vec2之間的歐氏距離 return numpy.sqrt(numpy.sum(numpy.square(vec1 - vec2))) def loadDataSet(inFile): # 載入資料測試資料集 # 資料由文字儲存,為二維座標 inDate = codecs.open(inFile, 'r', 'utf-8').readlines() dataSet = list() for line in inDate: line = line.strip() strList = re.split('[ ]+', line) # 去除多餘的空格 # print strList[0], strList[1] numList = list() for item in strList: num = float(item) numList.append(num) # print numList dataSet.append(numList) return dataSet # dataSet = [[], [], [], ...] def initCentroids(dataSet, k): # 初始化k個質心,隨機獲取 return random.sample(dataSet, k) # 從dataSet中隨機獲取k個數據項返回 def minDistance(dataSet, centroidList): # 對每個屬於dataSet的item,計算item與centroidList中k個質心的歐式距離,找出距離最小的, # 並將item加入相應的簇類中 # dataSet 取出一條資料 然後分別與centroidList中的k的值進行歐氏距離的計算比較與哪個距離最短,儲存到對應的分類下 clusterDict = dict() # 用dict來儲存簇類結果 for item in dataSet: vec1 = numpy.array(item) # 取出一條資料轉換成array形式 flag = 0 # 簇分類標記,根據距離比較將該條資料記錄到對應的分類下 minDis = float("inf") # 比較值為最大值 #迴圈簇分類集合中的值 for i in range(len(centroidList)): vec2 = numpy.array(centroidList[i]) distance = calcuDistance(vec1, vec2) # 計算相應的歐式距離 if distance < minDis: minDis = distance flag = i # 迴圈結束時,flag儲存的是與當前item距離最近的那個簇標記 if flag not in clusterDict.keys(): # 簇標記不存在,進行初始化 clusterDict[flag] = list() clusterDict[flag].append(item) # 加入相應的類別中 return clusterDict # 返回新的聚類結果 def getCentroids(clusterDict): # 得到k個質心 centroidList = list() for key in clusterDict.keys(): centroid = numpy.mean(numpy.array(clusterDict[key]), axis=0) # 計算每列的均值,即找到質心 # print key, centroid centroidList.append(centroid) return numpy.array(centroidList).tolist() def getVar(clusterDict, centroidList): # 計算簇集合間的均方誤差 # 將簇類中各個向量與質心的距離進行累加求和 sum = 0.0 for key in clusterDict.keys(): vec1 = numpy.array(centroidList[key]) print(vec1) distance = 0.0 for item in clusterDict[key]: vec2 = numpy.array(item) distance += calcuDistance(vec1, vec2) sum += distance return sum def showCluster(centroidList, clusterDict): # 展示聚類結果 colorMark = ['or', 'ob', 'og', 'ok', 'oy', 'ow'] # 不同簇類的標記 'or' --> 'o'代表圓,'r'代表red,'b':blue centroidMark = ['dr', 'db', 'dg', 'dk', 'dy', 'dw'] # 質心標記 同上'd'代表稜形 for key in clusterDict.keys(): plt.plot(centroidList[key][0], centroidList[key][1], centroidMark[key], markersize=12) # 畫質心點 for item in clusterDict[key]: plt.plot(item[0], item[1], colorMark[key]) # 畫簇類下的點 plt.show() if __name__ == '__main__': inFile = "test.txt" # 資料集檔案 dataSet = loadDataSet(inFile) # 載入資料集 centroidList = initCentroids(dataSet, 4) # 初始化質心,設定k=4 clusterDict = minDistance(dataSet, centroidList) # 第一次聚類迭代 newVar = getVar(clusterDict, centroidList) # 獲得均方誤差值,通過新舊均方誤差來獲得迭代終止條件 oldVar = -0.0001 # 舊均方誤差值初始化為-1 print ('***** 第1次迭代 *****') print print( '簇類') for key in clusterDict.keys(): print (key, ' --> ', clusterDict[key]) print ('k個均值向量: ', centroidList) print ('平均均方誤差: ', newVar) print() showCluster(centroidList, clusterDict) # 展示聚類結果 k = 2 while abs(newVar - oldVar) >= 0.0001: # 當連續兩次聚類結果小於0.0001時,迭代結束 centroidList = getCentroids(clusterDict) # 獲得新的質心 clusterDict = minDistance(dataSet, centroidList) # 新的聚類結果 oldVar = newVar newVar = getVar(clusterDict, centroidList) print('***** 第%d次迭代 *****' % k) print print ('簇類') for key in clusterDict.keys(): print (key, ' --> ', clusterDict[key]) print ('k個均值向量: ', centroidList) print ('平均均方誤差: ', newVar) print() showCluster(centroidList, clusterDict) # 展示聚類結果 k += 1