原帖地址:http://www.opencvchina.com/thread-749-1-1.html
k-means是一種聚類算法,這種算法是依賴於點的鄰域來決定哪些點應該分在一個組中。當一堆點都靠的比較近,那這堆點應該是分到同一組。使用k-means,可以找到每一組的中心點。當然,聚類算法並不局限於2維的點,也可以對高維的空間(3維,4維,等等)的點進行聚類,任意高維的空間都可以。
上圖中的彩色部分是一些二維空間點。上圖中已經把這些點分組了,並使用了不同的顏色對各組進行了標記。這就是聚類算法要做的事情。
K-means算法:
這個算法的輸入是:
1:點的數據(這里並不一定指的是坐標,其實可以說是向量)
2:K,聚類中心的個數(即要把這一堆數據分成幾組)
所以,在處理之前,你先要決定將要把這一堆數據分成幾組,即聚成幾類。但並不是在所有情況下,你都事先就能知道需要把數據聚成幾類的。但這也並不意味着使用k-means就不能處理這種情況,下文中會有講解。
把相應的輸入數據,傳入k-means算法后,當k-means算法運行完后,該算法的輸出是:
1:標簽(每一個點都有一個標簽,因為最終任何一個點,總會被分到某個類,類的id號就是標簽)
2:每個類的中心點。
標簽,是表示某個點是被分到哪個類了。例如,在上圖中,實際上有4中“標簽”,每個“標簽”使用不同的顏色來表示。所有黃色點我們可以用標簽0表示,所有橘色點可以用標簽1來表示,等等。
主體算法分析:
步驟1:得到數據集
在本文中,使用上圖的二維坐標(x,y)向量為數據集。假設我們要將這些點聚成5類,即k=5。我們可以看出,有3個類離的比較遠,有兩個類離得比較近,幾乎要混合在一起了。
當然,數據集不一定是坐標,假如你要對彩色圖像進行聚類,那么你的向量就可以是(b,g,r),如果使用的是hsv顏色空間,那還可以使用(h,s,v),當然肯定可以有不同的組合例如(b*b,g*r,r*b) ,(h*b,s*g,v*v)等等。
步驟2:產生初始的類中心
在本文中,初始的類的中心點是隨機產生的。如上圖的紅色點所示,是本文隨機產生的初始點。注意觀察那兩個離得比較近的類,它們幾乎要混合在一起,看看算法是如何將它們分開的。
類的初始中心點是隨機產生的。算法會不斷迭代來矯正這些中心點,並最終得到比較靠近真實中心點的一組中心點。當然,最終的結果不一定就是真實的那一組中心點,算法會盡量向真實的靠近。
步驟3:根據中心點,划分其他點的歸屬(歸屬於哪個類)
每個點(除了中心點的其他點)都計算與5個中心點的距離,選出一個距離最小的(例如該點與第2個中心點的距離是5個距離中最小的),那么該點就歸屬於該類.上圖是點的歸類結果示意圖.
步驟4:重新計算中心點
經過步驟3后,每一個中心center(i)點都有它的”管轄范圍”,由於這個中心點不一定是這個管轄范圍的真正中心點,所以要重新計算中心點,計算的方法有很多種,最簡單的一種是,直接計算該管轄范圍內所有點的均值,做為心的中心點new_center(i)。
如果重新計算的中心點new_center(i)與原來的中心點center(i)的距離大於一定的閾值(該閾值可以設定),那么認為算法尚未收斂,使用new_center(i)代替center(i)(如圖,中心點從紅色點轉移到綠色點),轉步驟3;否則,認為算法已經收斂,則new_center(i)就是最終的中心點。
步驟5:結束
現在,所有的中心都不再移動,即算法已經收斂。當然,也許這些中心點還沒有達到你要的精度,由於計算這些中心點的准確性,會受初始中心點設置的影響。所以,如果初始中心設置的很糟糕,那么得出來的結果也會不理想。
問題及解決方法
使用k-means時,我們遇到了兩個困難。
(1)在事先不知道要聚幾類的情況下,該怎么辦?
可以從K=1開始,並且k值不斷的增加,通常,隨着k的增加,類中的方差會急劇的下降,當k達到一定大的時候,方差的下降會明顯減慢(至於慢道何種程度,可以設閾值),此時,就選取到了最佳的k值。
(2)初始中心點的設定
如果初始值沒設置好,肯定也不能獲得理想的聚類效果。針對這種情況,這里提供兩種方法:隨機的選取多組中心點,在每一組中心點上,都把kmeans算法運行一次。最后,在選取類間方差最小的一組。通過設定的選初始值方法(這里提供一種,當然自己也可以去構想其他的方法):
1:在數據集上隨機選擇一個點,做為第一個中心點;
2:在數據集上,選取離第一個中心點最遠的一個點做為第二個中心點。
3:在數據集上,選取離第一個和第二個中心最遠的點,做為第三個中心。
4:依此計算后續的中心點