因爲這個是K-means的改進算法,因此優缺點與之相同。html
1.要了解這個首先應該瞭解K-means算法,能夠看這裏這個算法的思想是:首先將全部點做爲一個簇,而後將該簇一分爲二。以後選擇能最大程度下降聚類代價函數(也就是偏差平方和)的簇劃分爲兩個簇(或者選擇最大的簇等,選擇方法多種)。以此進行下去,直到簇的數目等於用戶給定的數目k爲止。
2.以上隱含着一個原則是:由於聚類的偏差平方和可以衡量聚類性能,該值越小表示數據點月接近於它們的質心,聚類效果就越好。因此咱們就須要對偏差平方和最大的簇進行再一次的劃分,由於偏差平方和越大,表示該簇聚類越很差,越有多是多個簇被當成一個簇了,因此咱們首先須要對這個簇進行劃分。
3.關於二分K-means的優勢《Machine Learning in Action》說的是可以克服K-means收斂於局部最小,可是想了一下感受這個並不能保證收斂到全局最優值(並且後面運行代碼結果也會出現不太好的狀況,不知道這算不算是個證據)
4.經過查閱一些資料和總結,二分K-means聚類的優勢有:web
因此說這個算法也並不可以保證徹底不受K的影響必定歸到全局最小,只是相對較優,而且還有了必定的速度提高。理解有誤差歡迎指正。算法
biKmeans(dataSet, k, distMeas=distEclud)
這個函數實現了二分算法,過程大致以下(代碼中註釋已經很詳細了):
1.初始化所有點的質心,並創建所須要的數據存儲結構
2.對每個簇嘗試二分(最開始就是一個簇),選出最好的
3.更新各個簇的元素個數app
1 def biKmeans(dataSet, k, distMeas=distEclud): 2 m = shape(dataSet)[0] 3 clusterAssment = mat(zeros((m,2)))#記錄簇分配的結果及偏差 4 centroid0 = mean(dataSet, axis=0).tolist()[0]#計算整個數據集的質心 5 centList =[centroid0] #create a list with one centroid 6 for j in range(m):#計算初始聚類點與其餘點的距離 7 clusterAssment[j,1] = distMeas(mat(centroid0), dataSet[j,:])**2 8 while (len(centList) < k): 9 lowestSSE = inf 10 for i in range(len(centList)):#嘗試劃分每一簇 11 ptsInCurrCluster = dataSet[nonzero(clusterAssment[:,0].A==i)[0],:]#get the data points currently in cluster i 12 centroidMat, splitClustAss = kMeans(ptsInCurrCluster, 2, distMeas)#對這個簇運行一個KMeans算法,k=2 13 sseSplit = sum(splitClustAss[:,1])#compare the SSE to the currrent minimum 14 sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:,0].A!=i)[0],1]) 15 print "sseSplit, and notSplit: ",sseSplit,sseNotSplit 16 if (sseSplit + sseNotSplit) < lowestSSE:##劃分後更好的話 17 bestCentToSplit = i 18 bestNewCents = centroidMat 19 bestClustAss = splitClustAss.copy() 20 lowestSSE = sseSplit + sseNotSplit 21 bestClustAss[nonzero(bestClustAss[:,0].A == 1)[0],0] = len(centList) #更新簇的分配結果change 1 to 3,4, or whatever 22 bestClustAss[nonzero(bestClustAss[:,0].A == 0)[0],0] = bestCentToSplit 23 print 'the bestCentToSplit is: ',bestCentToSplit 24 print 'the len of bestClustAss is: ', len(bestClustAss) 25 centList[bestCentToSplit] = bestNewCents[0,:].tolist()[0]#replace a centroid with two best centroids 26 centList.append(bestNewCents[1,:].tolist()[0]) 27 clusterAssment[nonzero(clusterAssment[:,0].A == bestCentToSplit)[0],:]= bestClustAss#reassign new clusters, and SSE 28 return mat(centList), clusterAssment