github:kmeans代碼實現1、kmeans代碼實現2(包含二分k-means)
本文算法均使用python3實現html
對於"監督學習"(supervised learning),其訓練樣本是帶有標記信息的,而且監督學習的目的是:對帶有標記的數據集進行模型學習,從而便於對新的樣本進行分類。而在「無監督學習」(unsupervised learning)中,訓練樣本的標記信息是未知的,目標是經過對無標記訓練樣本的學習來揭示數據的內在性質及規律,爲進一步的數據分析提供基礎。對於無監督學習,應用最廣的即是"聚類"(clustering)。
「聚類算法」試圖將數據集中的樣本劃分爲若干個一般是不相交的子集,每一個子集稱爲一個「簇」(cluster),經過這樣的劃分,每一個簇可能對應於一些潛在的概念或類別。
咱們能夠經過下面這個圖來理解:
python
kmeans算法又名k均值算法。其算法思想大體爲:先從樣本集中隨機選取 $ k $ 個樣本做爲簇中心,並計算全部樣本與這 $ k $ 個「簇中心」的距離,對於每個樣本,將其劃分到與其距離最近的「簇中心」所在的簇中,對於新的簇計算各個簇的新的「簇中心」。
根據以上描述,咱們大體能夠猜想到實現kmeans算法的主要三點:
(1)簇個數 $ k $ 的選擇
(2)各個樣本點到「簇中心」的距離
(3)根據新劃分的簇,更新「簇中心」git
(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) 更新「簇中心」
對於劃分好的各個簇,計算各個簇中的樣本點均值,將其均值做爲新的簇中心。github
輸入:訓練數據集 $ 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} $算法
爲避免運行時間過長,一般設置一個最大運行輪數或最小調整幅度閾值,若達到最大輪數或調整幅度小於閾值,則中止運行。
過程以下圖:
機器學習
kmeans算法因爲初始「簇中心」點是隨機選取的,所以最終求得的簇的劃分與隨機選取的「簇中心」有關,也就是說,可能會形成多種 $ k $ 個簇的劃分狀況。這是由於kmeans算法收斂到了局部最小值,而非全局最小值。ide
基於kmeans算法容易使得結果爲局部最小值而非全局最小值這一缺陷,對算法加以改進。使用一種用於度量聚類效果的指標SSE(Sum of Squared Error),即對於第 $ i $ 個簇,其SSE爲各個樣本點到「簇中心」點的距離的平方的和,SSE值越小表示數據點越接近於它們的「簇中心」點,聚類效果也就越好。以此做爲劃分簇的標準。
算法思想是:先將整個樣本集做爲一個簇,該「簇中心」點向量爲全部樣本點的均值,計算此時的SSE。若此時簇個數小於 $ k $ ,對每個簇進行kmeans聚類($ k=2 $) ,計算將每個簇一分爲二後的總偏差SSE,選擇SSE最小的那個簇進行劃分操做。函數
輸入:訓練數據集 $ 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} $學習
二分k-means算法再也不隨機選取簇中心,而是從一個簇出發,根據聚類效果度量指標SSE來判斷下一步應該對哪個簇進行劃分,所以該方法不會收斂到局部最小值,而是收斂到全局最小值。google
引用及參考:
[1]《機器學習》周志華著
[2]《機器學習實戰》Peter Harrington著
[3]https://blog.csdn.net/google19890102/article/details/26149927
寫在最後:本文參考以上資料進行整合與總結,屬於原創,文章中可能出現理解不當的地方,如有所看法或異議可在下方評論,謝謝!
若需轉載請註明:http://www.javashuo.com/article/p-kacaayof-ch.html