二分K-means算法

二分K-means聚類(bisecting K-means)

算法優缺點:

因爲這個是K-means的改進算法,因此優缺點與之相同。html

算法思想:

1.要了解這個首先應該瞭解K-means算法,能夠看這裏這個算法的思想是:首先將全部點做爲一個簇,而後將該簇一分爲二。以後選擇能最大程度下降聚類代價函數(也就是偏差平方和)的簇劃分爲兩個簇(或者選擇最大的簇等,選擇方法多種)。以此進行下去,直到簇的數目等於用戶給定的數目k爲止。
2.以上隱含着一個原則是:由於聚類的偏差平方和可以衡量聚類性能,該值越小表示數據點月接近於它們的質心,聚類效果就越好。因此咱們就須要對偏差平方和最大的簇進行再一次的劃分,由於偏差平方和越大,表示該簇聚類越很差,越有多是多個簇被當成一個簇了,因此咱們首先須要對這個簇進行劃分。
3.關於二分K-means的優勢《Machine Learning in Action》說的是可以克服K-means收斂於局部最小,可是想了一下感受這個並不能保證收斂到全局最優值(並且後面運行代碼結果也會出現不太好的狀況,不知道這算不算是個證據)
4.經過查閱一些資料和總結,二分K-means聚類的優勢有:web

  • 二分K均值算法能夠加速K-means算法的執行速度,由於它的類似度計算少了
  • 不受初始化問題的影響,由於這裏不存在隨機點的選取,且每一步都保證了偏差最小

因此說這個算法也並不可以保證徹底不受K的影響必定歸到全局最小,只是相對較優,而且還有了必定的速度提高。理解有誤差歡迎指正。算法

函數:

biKmeans(dataSet, k, distMeas=distEclud)
這個函數實現了二分算法,過程大致以下(代碼中註釋已經很詳細了):
1.初始化所有點的質心,並創建所須要的數據存儲結構
2.對每個簇嘗試二分(最開始就是一個簇),選出最好的
3.更新各個簇的元素個數
app

  1.  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

     

聚類的效果應該仍是不錯的,比K-means要好
 

 

機器學習筆記索引

相關文章
相關標籤/搜索