二分K-means算法


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

算法優缺點:

由於這個是K-means的改進算法,所以優缺點與之相同。

算法思想:

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

  • 二分K均值算法可以加速K-means算法的執行速度,因為它的相似度計算少了
  • 不受初始化問題的影響,因為這里不存在隨機點的選取,且每一步都保證了誤差最小

所以說這個算法也並不能夠保證完全不受K的影響一定歸到全局最小,只是相對較優,並且還有了一定的速度提升。理解有偏差歡迎指正。

函數:

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

  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要好
 

 

機器學習筆記索引




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM