kmeans算法理解及代碼實現


github:kmeans代碼實現1kmeans代碼實現2(包含二分k-means)
本文算法均使用python3實現


1 聚類算法

  對於"監督學習"(supervised learning),其訓練樣本是帶有標記信息的,並且監督學習的目的是:對帶有標記的數據集進行模型學習,從而便於對新的樣本進行分類。而在“無監督學習”(unsupervised learning)中,訓練樣本的標記信息是未知的目標是通過對無標記訓練樣本的學習來揭示數據的內在性質及規律,為進一步的數據分析提供基礎。對於無監督學習,應用最廣的便是"聚類"(clustering)
  “聚類算法”試圖將數據集中的樣本划分為若干個通常是不相交的子集,每個子集稱為一個“簇”(cluster),通過這樣的划分,每個簇可能對應於一些潛在的概念或類別。
  我們可以通過下面這個圖來理解:

  上圖是未做標記的樣本集,通過他們的分布,我們很容易對上圖中的樣本做出以下幾種划分。   當需要將其划分為兩個簇時,即 $ k=2 $ 時:
  當需要將其划分為四個簇時,即 $ k=4 $ 時:
  那么計算機是如何進行這樣的划分的呢?這就需要**聚類算法**來進行實現了。本文主要針對聚類算法中的一種——**kmeans算法**進行介紹。

2 kmeans算法

  kmeans算法又名k均值算法。其算法思想大致為:先從樣本集中隨機選取 $ k $ 個樣本作為簇中心,並計算所有樣本與這 $ k $ 個“簇中心”的距離,對於每一個樣本,將其划分到與其距離最近的“簇中心”所在的簇中,對於新的簇計算各個簇的新的“簇中心”。
  根據以上描述,我們大致可以猜測到實現kmeans算法的主要三點:
  (1)簇個數 $ k $ 的選擇
  (2)各個樣本點到“簇中心”的距離
  (3)根據新划分的簇,更新“簇中心”

2.1 kmeans算法要點

  (1) $ k $ 值的選擇
     $ k $ 的選擇一般是按照實際需求進行決定,或在實現算法時直接給定 $ k $ 值。
  (2) 距離的度量
     給定樣本 $ x^{(i)} = \lbrace x_1^{(i)},x_2^{(i)},,...,x_n^{(i)}, \rbrace 與 x^{(j)} = \lbrace x_1^{(j)},x_2^{(j)},,...,x_n^{(j)}, \rbrace ,其中 i,j=1,2,...,m,表示樣本數,n表示特征數 $ 。距離的度量方法主要分為以下幾種:
    (2.1)有序屬性距離度量(離散屬性 $ \lbrace1,2,3 \rbrace $ 或連續屬性):
      閔可夫斯基距離(Minkowski distance): $$ dist_{mk}(x^{(i)},x^{(j)})=(\sum_{u=1}^n |x_u^{(i)}-x_u^{(j)}|^p)^{\frac{1}{p}} $$
      歐氏距離(Euclidean distance),即當 $ p=2 $ 時的閔可夫斯基距離: $$ dist_{ed}(x^{(i)},x^{(j)})=||x^{(i)}-x^{(j)}||2=\sqrt{\sum{u=1}^n |x_u^{(i)}-x_u^{(j)}|^2} $$
      曼哈頓距離(Manhattan distance),即當 $ p=1 $ 時的閔可夫斯基距離: $$ dist_{man}(x^{(i)},x^{(j)})=||x^{(i)}-x^{(j)}||1=\sum{u=1}^n |x_u^{(i)}-x_u^{(j)}| $$
    (2.2)無序屬性距離度量(比如{飛機,火車,輪船}):
      VDM(Value Difference Metric): $$ VDM_p(x_u^{(i)},x_u^{(j)}) = \sum_{z=1}^k \left|\frac{m_{u,x_u^{(i)},z}}{m_{u,x_u^{(i)}}} - \frac{m_{u,x_u^{(j)},z}}{m_{u,x_u^{(j)}}} \right|^p $$
      其中 $ m_{u,x_u^{(i)}} $ 表示在屬性 $ u $ 上取值為 $ x_u^{(i)} $ 的樣本數, $ m_{u,x_u^{(i)},z} $ 表示在第 $ z $ 個樣本簇中屬性 $ u $ 上取值為 $ x_u^{(i)} $ 的樣本數, $ VDM_p(x_u^{(i)},x_u^{(j)}) $ 表示在屬性 $ u $ 上兩個離散值 $ x_u^{(i)} 與 x_u^{(i)} $ 的 $ VDM $ 距離 。
    (2.3)混合屬性距離度量,即為有序與無序的結合: $$ MinkovDM_p(x^{(i)},x^{(j)}) = \left( \sum_{u=1}^{n_c} | x_u^{(i)} - x_u^{(j)} | ^p + \sum_{u=n_c +1}^n VDM_p (x_u^{(i)},x_u^{(j)}) \right) ^{\frac{1}{p}} $$
      其中含有 $ n_c $ 個有序屬性,與 $ n-n_c $ 個無序屬性。
    本文數據集為連續屬性,因此代碼中主要以歐式距離進行距離的度量計算。
  (3) 更新“簇中心”
     對於划分好的各個簇,計算各個簇中的樣本點均值,將其均值作為新的簇中心。

2.2 kmeans算法過程


  輸入:訓練數據集 $ D ={x^{(1)},x^{(2)},...,x^{(m)}}$ ,聚類簇數 $ k $ ;
  過程:函數 $ kMeans(D, k, maxIter) $ .
  1:從 $ D $ 中隨機選擇 $ k $ 個樣本作為初始“簇中心”向量: $ {\mu^{(1)},\mu^{(2)},...,,\mu^{(k)}} $ :
  2:repeat
  3:  令 $ C_i = \emptyset (1 \leq i \leq k ) $
  4:  for $ j= 1,2,...,m $ do
  5:    計算樣本 $ x^{(j)} $ 與各“簇中心”向量 $ \mu^{(i)} (1 \leq i \leq k ) $ 的歐式距離
  6:    根據距離最近的“簇中心”向量確定 $ x^{(j)} $ 的簇標記: $ \lambda_j = argmin_{i \in \lbrace 1,2,...,k \rbrace}d_{ji} $
  7:    將樣本 $ x^{(j)} $ 划入相應的簇: $ C_{\lambda_j} = C_{\lambda_j} \bigcup \lbrace x^{(j)} \rbrace $ ;
  8:  end for
  9:  for $ i= 1,2,...,k $ do
  10:    計算新“簇中心”向量: $ (\mu^{(i)})' = \frac{1}{|C_i|} \sum_{x \in C_i}x $ ;
  11:    if $ (\mu^{(i)})' = \mu^{(i)} $ then
  12:      將當前“簇中心”向量 $ \mu^{(i)} $ 更新為 $ (\mu^{(i)})' $
  13:    else
  14:      保持當前均值向量不變
  15:    end if
  16:  end for
  17:  else
  18:until 當前“簇中心”向量均未更新
  輸出:簇划分 $ C={C_1,C_2,...,C_K} $


  為避免運行時間過長,通常設置一個最大運行輪數或最小調整幅度閾值,若達到最大輪數或調整幅度小於閾值,則停止運行。
  過程如下圖:

2.2 kmeans算法分析

  kmeans算法由於初始“簇中心”點是隨機選取的,因此最終求得的簇的划分與隨機選取的“簇中心”有關,也就是說,可能會造成多種 $ k $ 個簇的划分情況。這是因為kmeans算法收斂到了局部最小值,而非全局最小值。


3 二分k-means算法

  基於kmeans算法容易使得結果為局部最小值而非全局最小值這一缺陷,對算法加以改進。使用一種用於度量聚類效果的指標SSE(Sum of Squared Error),即對於第 $ i $ 個簇,其SSE為各個樣本點到“簇中心”點的距離的平方的和,SSE值越小表示數據點越接近於它們的“簇中心”點,聚類效果也就越好。以此作為划分簇的標准。
  算法思想是:先將整個樣本集作為一個簇,該“簇中心”點向量為所有樣本點的均值,計算此時的SSE。若此時簇個數小於 $ k $ ,對每一個簇進行kmeans聚類($ k=2 $) ,計算將每一個簇一分為二后的總誤差SSE,選擇SSE最小的那個簇進行划分操作。

3.1 kmeans算法過程


  輸入:訓練數據集 $ D ={x^{(1)},x^{(2)},...,x^{(m)}}$ ,聚類簇數 $ k $ ;
  過程:函數 $ kMeans(D, k, maxIter) $ .
  1:將所有點看做一個簇,計算此時“簇中心”向量:$ \mu^{(1)} = \frac{1}{m} \sum_{x \in D}x $
  2:while $ “簇中心”個數h < k $ :
  3:  for $ i= 1,2,...,h $ do
  4:    將第 $ i $ 個簇使用 kmeans算法進行划分,其中 $ k = 2 $
  5:    計算划分后的誤差平方和 $ SSE_i $
  5:  比較 $ k $ 種划分的SSE值,選擇SSE值最小的那種簇划分進行划分
  5:  更新簇的分配結果
  5:  添加新的“簇中心”
  18:until 當前“簇中心”個數達到 $ k $
  輸出:簇划分 $ C={C_1,C_2,...,C_K} $


3.2 二分k-means算法分析

  二分k-means算法不再隨機選取簇中心,而是從一個簇出發,根據聚類效果度量指標SSE來判斷下一步應該對哪一個簇進行划分,因此該方法不會收斂到局部最小值,而是收斂到全局最小值。


引用及參考:
[1]《機器學習》周志華著
[2]《機器學習實戰》Peter Harrington著
[3]https://blog.csdn.net/google19890102/article/details/26149927

寫在最后:本文參考以上資料進行整合與總結,屬於原創,文章中可能出現理解不當的地方,若有所見解或異議可在下方評論,謝謝!
若需轉載請注明https://www.cnblogs.com/lliuye/p/9144312.html


免責聲明!

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



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