3-3 K-means sk

在使用分割式分群法(partitional clustering)時,我們必須先指定群聚的數目,然後藉著反覆疊代運算,逐次降低一個誤差目標函數的值,直到目標函數不再變化,就達到分群的最後結果。

在所有的分割式分群法之中,最基本的方法,就是所謂的 K-means 分群法(k-means clustering),又稱為Forgy's algorithm [6]。其主要目標是要在大量高維的資料點中找出具有代表性的資料點,這些資料點可以稱為是群中心(cluster centers)、代表點(prototypes)、codewords等,然後在根據這些群中心,進行後續的處理,這些處理可以包含:

分割式分群法的目的是希望盡量減小每個群聚中,每一點與群中心的距離平方誤差(square error)。假設我們現在有一組包含c個群聚的資料,其中第 k 個群聚可以用集合 Gk 來表示,假設 Gk 包含nk筆資料 {x1, x2, …, xnk),此群聚中心為yk,則該群聚的平方誤差 ek可以定義為:
ek = Si |xi-yk|2,其中 xi 是屬於第 k 群的資料點。
而這c個群聚的總和平方誤差E便是每個群聚的平方誤差總和,可稱為分群的「誤差函數」(error function)或「失真度」(distortion):
E = Sk=1~c ek
我們分群的方法,就變成是一個最佳化的問題,換句話說,我們要如何選取 c 個群聚以及相關的群中心,使得 E 的值為最小。

我們也可以使用另一套數來描述,給定一組 n 點資料 X = {x1, ..., xn},每一點都有 d 維,k-means 分群法的任務是找到一組 m 個代表點 Y = {y1, ..., ym},每一點也是d維,以使下列的目標函數越小越好:

J(X; Y, U) = Si=1n|xi-yk|2
其中 xi屬於 Gk 而且 yk 是 Gk 的代表點。同時在上述目標函數中,U 是一個 mxn 的分組矩陣,每一個元素值都是 0 或 1,而且每一直行的總和等於 1,如果 U(i, j) = 1,代表第i個資料點是屬於第j組。

若要直接對上述目標函數進行最小化,是一件蠻困難的事,因為這個目標函數有 m*n+m*d個可變參數,同時又有n個限制條件,很難直接採用傳統的方式來進行最佳化,但我們可以觀察到兩個現象:

  1. 當Y(群中心)固定時,我們可以很容易地找到對應的U(資料分群方式),使J(X; Y, U)的值為最小。此最佳的U值,即代表最佳的分群方式,因此若將每個資料點歸類到距離最近的代表點,即可完成此目標。
  2. 當U(資料分群方式)固定實,我們也可以很快地找到對應的Y(群中心),使J(X; Y, U)的值為最小。此最佳的Y集合,代表每個代表點至其組員的距離平方和為最小,因此此最佳的Y集合即是每一群的平均點。
在演算法開始進行前,我們必須事先決定好預期分群的群聚數目。假設預期的分群群聚數目為c,則根據上述觀察,我們可以經由下列步驟來進行 k-means 分群法:
  1. 隨機選取 c 個資料點,將之分別視為c 個群聚的群中心,這就是Y。
  2. 由固定的Y,產生最佳的U。換句話說,對每一個資料點x,尋找與之最接近的群中心,並將x加入該群聚。
  3. 計算目標函數 J(X; Y, U),如果保持不變,代表分群結果已經穩定不變,所以可以結束此疊代方法。
  4. 再由固定的U,產生最佳的Y。跳回第2個步驟。
在上述方法中,我們是先找群中心,再開始反覆疊代的過程。事實上,我們也可以先進行任意分群,然後再進行反覆疊代的過程,得到的結果應該很類似。

這是一個反覆的過程,但在整個迴圈的過程中,我們可以保證J(X; Y, U)絕對不會遞增(可用數學證明,請見上述前述兩點觀察),只會遞減或維持不變,一旦維持不變,我們就可以跳出迴圈、結束演算法。

Hint
k-means 分群法是屬於「向量量化」(Vector Quantization,簡稱 VQ)的一個基本方法,所以在 Machine Learning Toolbox 中,k-means 的主要函示是 kMeansClustering.m

下面這個範例,顯示k-means分群法對於一組二維資料的分群效果:

Example 1: kmeans01.m% ====== Get the data set DS = dcData(5); subplot(2,2,1); plot(DS.input(1,:), DS.input(2,:), '.'); axis tight, axis image % ====== Run kmeans centerNum=4; [center, U, distortion, allCenters] = kMeansClustering(DS.input, centerNum); % ====== Plot the result subplot(2,2,2); vqDataPlot(DS.input, center); subplot(2,1,2); plot(distortion, 'o-'); xlabel('No. of iterations'); ylabel('Distortion'); grid on

在上圖中,左圖是在迭代過程中,目標函數遞減的圖形,右圖則是最後的分群結果。在上述範例中,由於啟始中心點是由亂數產生,所以每次執行程式碼,所得到的圖形都會不太一樣。

下面這個範例,我們使用同一組二維資料來進行 kmeans,並顯示在迭代過程中,中心點的移動過程:

Example 2: kmeans02.m% ====== Get the data set DS = dcData(5); centerNum=4; % ====== Get initial cluster centers initCenter=vqCenterInit(DS.input, centerNum); subplot(2,2,1); vqDataPlot(DS.input, initCenter); % ====== Run k-means to get the final cluster centers [center, U, distortion, allCenters] = kMeansClustering(DS.input, initCenter); subplot(2,2,2); vqDataPlot(DS.input, center); % ====== Plot the distortion subplot(2,2,3); plot(1:length(distortion), distortion, 'o-'); xlabel('No. of iterations'); ylabel('Distortion'); grid on; axis tight % ====== Plot the moving paths of the centers subplot(2,2,4); for i=1:centerNum xData=allCenters(1,i,:); xData=xData(:); yData=allCenters(2,i,:); yData=yData(:); line(xData, yData, 'color', getColor(i), 'lineWidth', 3); end box on; axis image

在上圖中: 在上述資料中,我們可以很明顯地看出,資料原先就可以概分為四群,如果我們也設定群數等於4,然後開始跑k-means,所得到的結果通常是正確的,但是如何決定適當的群數,這是尚待解決的另一個問題,此問題通稱為cluster validation,請見後續章節的說明。

下面這個範例,顯示k-means分群法對於另一組二維資料(甜甜圈)的分群效果:

Example 3: kmeans03.m% ====== Get the data set DS = dcData(2); centerNum=8; % ====== Get initial cluster centers initCenter=vqCenterInit(DS.input, centerNum); clf; subplot(2,2,1); vqDataPlot(DS.input, initCenter); % ====== Run k-means to get the final cluster centers [center, U, distortion, allCenters] = kMeansClustering(DS.input, initCenter); subplot(2,2,2); vqDataPlot(DS.input, center); % ====== Plot the distortion subplot(2,2,3); plot(1:length(distortion), distortion, 'o-'); xlabel('No. of iterations'); ylabel('Distortion'); grid on; axis tight % ====== Plot the moving paths of the centers subplot(2,2,4); for i=1:centerNum xData=allCenters(1,i,:); xData=xData(:); yData=allCenters(2,i,:); yData=yData(:); line(xData, yData, 'color', getColor(i), 'lineWidth', 3); end box on; axis image

有關於k-means的方法,還需要注意幾點: 雖然我們可以證明此方法一定收斂,但是此方法只能找到目標函數的局部最小值(local minimum),我們並無法證明此方法所找到的群聚及群中心會使目標函數到達全域最小值(global minimum)。而事實上到目前為止,也沒有出現任何一種方法,能保證所找到的分群結果可使目標函數達到全域最小值。

由於我們只能找到局部最小值,所以如何選一組好的起始點,就變得很重要。以上述方法來說,若要選取 c 個起始中心典,常用的選取方法有下列幾種:

但是這些找出起始群中心點的方法也都無法保證達到更好的目標函數值。如果計算時間不是太久,建議在選取啟始群中心時,多試用不同的方法,找出多組啟始群中心,同時進行 k-means,最後再以目標函數最小的結果來作為最後分群的結果。

另一個可能發生的問題,就是在進行 k-means 的過程中,有可能出現一個空的群聚,此群聚是空集合,沒有資料點。碰到這種情況,一個簡單的解決方式,就是直接將另一個群聚拆解為兩個,這樣才能保持群聚數目的不變。至於要找那一個群聚來切成兩個,可已有下列標準:

上述討論的方法,通常又稱為 batch k-means algorithm,另一個類似的方法稱為 sequential k-means algorithm 或是 on-line k-mean algorithm,則是每當收集到一筆資料時,就可以更新群中心,方法如下:
  1. 隨機選取c的起始點,將之分別視為c個群聚的群中心
  2. 對每一個資料點x,尋找與之最接近的群中心,並將x加入該群聚,隨即計算新的群聚中心(該群聚中原有的資料點加上x後的平均向量)
  3. 檢查每一個資料點目前與之最接近的群聚中心是否和他的群聚分配一致,如果不是,則回到步驟二,反覆疊代,直到收斂。
一般而言, sequential k-mean algorithm的優點如下: 除非有特殊情況,否則我們很少使用 sequential k-mean algorithm。
Data Clustering and Pattern Recognition (資料分群與樣式辨認)