K-means演算法屬於無監督學習聚類演算法,其計算步驟還是挺簡單的,思想也挺容易理解,而且還可以在思想中體會到EM演算法的思想。
K-means 演算法的優缺點:
1.優點:容易實現
2.缺點:可能收斂到區域性最小值,在大規模資料集上收斂較慢
使用資料型別:數值型資料
以往的迴歸演算法、樸素貝葉斯、SVM等都是有類別標籤y的,因此屬於有監督學習,而K-means聚類演算法只有x,沒有y
在聚類問題中,我們的訓練樣本是
其中每個Xi都是n維實數。
樣本資料中沒有了y,K-means演算法是將樣本聚類成k個簇,具體演算法如下:
1、隨機選取K個聚類質心點,記為
2、重複以下過程直到收斂
{
對每個樣例 i ,計算其應該屬於的類:
對每個類 j ,重新計算質心:
}
其中K是我們事先給定的聚類數目,Ci 表示樣本 i 與K個聚類中最近的那個類,Ci的值是1到K中的一個,質心uj代表我們對屬於同一個類的樣本中心的猜測。解釋起來就是,
第一步:天空上的我們隨機抽取K個星星作為星團的質心,然後對於每一個星星 i,我們計算它到每一個質心uj的距離,選取其中距離最短的星團作為Ci,這樣第一步每個星星都有了自己所屬於的星團;
第二步:對每個星團Ci,我們重新計算它的質心uj(計算方法為對屬於該星團的所有點的座標求平均)不斷重複第一步和第二步直到質心變化很小或者是不變。
然後問題來了,怎麼樣才算質心變化很小或者是不變?或者說怎麼判定?答案就是畸變函式(distortion function),定義如下:
J函式表示每個樣本點到其質心的距離平方和,K-means的收斂就是要將 J 調整到最小,假設當前 J 值沒有達到最小值,那麼可以先固定每個類的質心 uj ,調整每個樣例的類別 Ci 來時 J 函式減少。同樣,固定 Ci ,調整每個類的質心 uj也可以是 J 減少。這兩個過程就是內迴圈中使 J 單調變小的過程。當 J 減小到最小的時候, u 和 c 也同時收斂。(該過程跟EM演算法其實還是挺像的)理論上可能出現多組 u 和 c 使 J 取得最小值,但這種情況實際上很少見。
由於畸變函式 J 是非凸函式,所以我們不能保證取得的最小值一定是全域性最小值,這說明k-means演算法質心的初始位置的選取會影響到最後最小值的獲取。不過一般情況下,k-means演算法達到的區域性最優已經滿足要求。如果不幸程式碼陷入區域性最優,我們可以選取不同的初始值跑多幾遍 k-means 演算法,然後選取其中最小的 J 對應的 u 和 c 輸出。
另一種收斂判斷:
實際我們編寫程式碼的時候,還可以通過判斷“每個點被分配的質心是否改變”這個條件來判斷聚類是否已經收斂
而上面所說的畸變函式則可以用來評估收斂的效果,具體將會在下面的例項中體現。
Matlab 實現
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
function kMeans clc clear K = 4; dataSet = load('testSet.txt'); [row,col] = size(dataSet); % 儲存質心矩陣 centSet = zeros(K,col); % 隨機初始化質心 for i= 1:col minV = min(dataSet(:,i)); rangV = max(dataSet(:,i)) - minV; centSet(:,i) = repmat(minV,[K,1]) + rangV*rand(K,1); end % 用於儲存每個點被分配的cluster以及到質心的距離 clusterAssment = zeros(row,2); clusterChange = true; while clusterChange clusterChange = false; % 計算每個點應該被分配的cluster for i = 1:row % 這部分可能可以優化 minDist = 10000; minIndex = 0; for j = 1:K distCal = distEclud(dataSet(i,:) , centSet(j,:)); if (distCal < minDist) minDist = distCal; minIndex = j; end end if minIndex ~= clusterAssment(i,1) clusterChange = true; end clusterAssment(i,1) = minIndex; clusterAssment(i,2) = minDist; end % 更新每個cluster 的質心 for j = 1:K simpleCluster = find(clusterAssment(:,1) == j); centSet(j,:) = mean(dataSet(simpleCluster',:)); end end figure %scatter(dataSet(:,1),dataSet(:,2),5) for i = 1:K pointCluster = find(clusterAssment(:,1) == i); scatter(dataSet(pointCluster,1),dataSet(pointCluster,2),5) hold on end %hold on scatter(centSet(:,1),centSet(:,2),300,'+') hold off end % 計算歐式距離 function dist = distEclud(vecA,vecB) dist = sqrt(sum(power((vecA-vecB),2))); end |
效果如下:
這是正常分類的情況,很明顯被分為了4個類,不同顏色代表不同的類,cluster的質心為 “ + ”
當然,這只是其中一種情況,很有可能我們會出現下面這種情況:
這就是上面所說的,K-means的缺點之一,隨機初始點的選擇可能會讓演算法陷入區域性最優解,這時候我們只需重新執行一次程式即可。
至於每一個看似都可以正常聚類的情況呢,我們則利用上面所說的“畸變函式”來衡量聚類的效果,當然是J越小聚類效果越好。
實際使用的時候,我們只需多次執行程式,選取J最小的聚類效果。