1、K-均值聚類算法
K-均值聚類的目的是將各個樣本點映射到距離某個質心最近的聚類中。假設樣本點爲$\textbf{x}^{t},t=1,2,3,...,n$,第$i$個聚類的質心爲$\textbf{m}_{i},i=1,2,...,k$。則,$\textbf{x}^{t}$屬於聚類$i$能夠表示爲:app
$||\textbf{x}^{t}-\textbf{m}_{i}||==min_{j}||\textbf{x}^{t}-\textbf{m}_{j}||$dom
其中,將$\textbf{x}^{t}$劃分爲聚類$i$的偏差表示爲:$||\textbf{x}^{t}-\textbf{m}_{i}||^{2}$。全體樣本的總偏差表示爲:ide
$E=\sum_{t}\sum_{i}b_{i}^{t}||\textbf{x}^{t}-\textbf{m}_{i}||^{2}$spa
其中,若是$||\textbf{x}^{t}-\textbf{m}_{i}||==min_{j}||\textbf{x}^{t}-\textbf{m}_{j}||$,$b_{i}^{t}=1$,不然,$b_{i}^{t}=0$。3d
選擇的質心必須可以最小化總偏差。可是因爲$b_{i}^{t}$的取值依賴於$\textbf{m}_{i}$,反過來$\textbf{m}_{i}$又依賴與$\textbf{m}_{i}$,這樣使得最小化問題沒法直接求解。對此,Kmeans的解法是首先肯定$\textbf{m}_{i}$的值,而後依據$\textbf{m}_{i}$的值去肯定每一個樣本點的$\textbf{m}_{i}$,有了$\textbf{m}_{i}$,在總偏差的公式中$\textbf{m}_{i}$爲已知項,只存在一個未知量,所以最小化問題得以求解。總偏差經過對$\textbf{m}_{i}$求導並令其等於0,獲得code
$\textbf{m}_{i}=\frac{\sum_{t}b_{i}^{t}\textbf{x}^{t}}{\sum_{t}b_{i}^{t}}$blog
這樣$\textbf{m}_{i}$得以更新。這是一個迭代的過程,一旦咱們計算出心的$\textbf{m}_{i}$,$\textbf{m}_{i}$就會發生改變並須要從新計算,這反過來又會影響$\textbf{m}_{i}$,這樣反反覆覆的重複,知道$\textbf{m}_{i}$再也不發生改變。ip
Kmeans的僞代碼:utf-8
初始化$\textbf{m}_{i},i=1,2,3...,k$。
Repeat
For 全部的$\textbf{x}^{t} \in X$
若是$||\textbf{x}^{t}-\textbf{m}_{i}||==min_{j}||\textbf{x}^{t}-\textbf{m}_{j}||$,$b_{i}^{t}=1$,不然,$b_{i}^{t}=0$
For 全部的$\textbf{m}_{i},i=1,2,...,k$
$\textbf{m}_{i}=\frac{\sum_{t}b_{i}^{t}\textbf{x}^{t}}{\sum_{t}b_{i}^{t}}$
Unitill $\textbf{m}_{i}$收斂
Kmeans的缺點是,它是一個局部搜索的過程,而且最終的$\textbf{m}_{i}$高度依賴於出事的$\textbf{m}_{i}$的選擇。所以初始化至關重要,常見的初始化方法包括:
1 # -*- coding=utf-8 -*- 2 """ 3 kmeans: 4 1. 加載數據 5 2. 計算歐式距離 6 3. 隨機生成k箇中心 7 """ 8 from mpl_toolkits.mplot3d import Axes3D 9 import matplotlib.pyplot as plt 10 from numpy import * 11 #加載文件數據,將標籤轉換爲數值類型 12 def loadDataSet(filename): 13 dataMat = [] 14 fr = open(filename, 'r') 15 #依次讀取數據,將每行數據分別加入到list中 16 for line in fr: 17 curLine = line.strip().split('\t') 18 #fltLine = map(float, curLine) 19 dataMat.append(curLine) 20 dataMat = mat(dataMat) 21 #標籤類型是string,須要轉換爲123這樣的 22 labels = dataMat[:,shape(dataMat)[1] - 1] 23 #set集合,獲得全部種類的標籤 24 labelsVec = [] 25 for i in range(shape(labels)[0]): 26 labelsVec.append(labels[i,0]) 27 labelsSet = set(labelsVec) 28 #print labelsSet 29 labelFlag = 0 30 #對相同的標籤賦予相同的值 31 for item in labelsSet: 32 index = nonzero(dataMat[:,shape(dataMat)[1] - 1].A == item)[0] 33 # print index 34 dataMat[index,shape(dataMat)[1] - 1] = labelFlag 35 labelFlag += 1 36 #print dataMat 37 fr.close() 38 dataMat = dataMat.tolist() 39 resMat = [] 40 #將string類型數據轉化爲數值類型 41 for i in range(shape(dataMat)[0]): 42 item = dataMat[i] 43 tmp = map(float, item) 44 resMat.append(tmp) 45 resMat = mat(resMat) 46 return resMat 47 #計算歐式距離 48 def distEclud(vecA, vecB): 49 return sqrt(sum(power(vecA - vecB, 2))) 50 #隨即選擇中心 51 def randCent(dataSet, k): 52 col = shape(dataSet)[1] 53 centrals = mat(zeros((k, col))) 54 for j in range(col): 55 #取最大最小值,注意max與min返回的是matrix,須要轉化爲單個數值 56 minJ = min(dataSet[:, j])[0, 0] 57 maxJ = max(dataSet[:, j])[0, 0] 58 rangeJ = maxJ - minJ 59 centrals[:, j] = minJ + rangeJ * random.rand(k, 1) 60 return centrals 61 #kmeans算法 62 def kMeans(dataSet, k, distMeans = distEclud, createCent = randCent): 63 #m表示數據集的size,行數 64 m = shape(dataSet)[0] 65 clusterAssment = mat(zeros((m, 2))) 66 #隨機生成k箇中心 67 centrals = createCent(dataSet, k) 68 #彙集再也不發生改變時中止循環 69 clusterChanged = True 70 while clusterChanged: 71 clusterChanged = False 72 #依次測量每一個數據點到各個彙集的距離 73 for i in range(m): 74 minDist = inf 75 minIndex = -1 76 #依次處理k個彙集的中心 77 for j in range(k): 78 distJI = distMeans(centrals[j,:], dataSet[i,:]) 79 #比較相對每一箇中心的距離,取最小距離對應的彙集 80 if distJI < minDist: 81 minDist = distJI 82 minIndex = j 83 #判斷第i個樣本點的最小距離是否發生變化 84 if clusterAssment[i,0] != minIndex: 85 clusterChanged = True 86 #將每一個樣本點按距離分配到不一樣的彙集中 87 clusterAssment[i,:] = minIndex, minDist**2 88 #print central 89 #更新各個彙集的中心 90 for cent in range(k): 91 ptsInClust = dataSet[nonzero(clusterAssment[:,0] == cent)[0]] 92 centrals[cent,:] = mean(ptsInClust, axis = 0) 93 return centrals, clusterAssment 94 datingSet = loadDataSet("/home/lichao/DataSet/datingtestset.txt") 95 dataSet = datingSet[:, 0:(shape(datingSet)[1] - 1)] 96 labelSet = datingSet[:, shape(datingSet)[1]-1] 97 central, clusterAssment = kMeans(dataSet, 3) 98 print "kmeans算法使用後獲得的k箇中心的座標:" 99 print central 100 fig = plt.figure() 101 ax = Axes3D(fig) 102 for i in range(shape(dataSet)[0]): 103 if clusterAssment[i,0] == 0: 104 ax.scatter(dataSet[i,0],dataSet[i,1],dataSet[i,2],c='r', marker='D') 105 elif clusterAssment[i,0] == 1: 106 ax.scatter(dataSet[i,0],dataSet[i,1],dataSet[i,2],c='b', marker='+') 107 else: 108 ax.scatter(dataSet[i,0],dataSet[i,1],dataSet[i,2],c='G', marker='o') 109 plt.show()
運行結果: