Kmeans聚類算法
1 Kmeans聚類算法的基本原理
K-means算法是最為經典的基於划分的聚類方法,是十大經典數據挖掘算法之一。K-means算法的基本思想是:以空間中k個點為中心進行聚類,對最靠近他們的對象歸類。通過迭代的方法,逐次更新各聚類中心的值,直至得到最好的聚類結果。
假設要把樣本集分為k個類別,算法描述如下:
(1)適當選擇k個類的初始中心,最初一般為隨機選取;
(2)在每次迭代中,對任意一個樣本,分別求其到k個中心的歐式距離,將該樣本歸到距離最短的中心所在的類;
(3)利用均值方法更新該k個類的中心的值;
(4)對於所有的k個聚類中心,重復(2)(3),類的中心值的移動距離滿足一定條件時,則迭代結束,完成分類。
Kmeans聚類算法原理簡單,效果也依賴於k值和類中初始點的選擇。
2 算法結構與實現方法
Kmeans算法相對比較簡單,本次算法實現采用C++語言,作為面向對象設計語言,為保證其良好的封裝性以及代碼重用性。軟件包含三個部分,即kmeans.h,kmeans.cpp和main.cpp。
在kmeans.h中,首先定義一個類,class KMeans,由於本算法實現需要對外部數據進行讀取和存儲,一次定義了一個容器Vector,其中數據類型為結構體st_point,包含三維點坐標以及一個char型的所屬類的ID。其次為函數的聲明。
圖4.1 程序基本機構與對應函數
在kmeans.cpp中具體給出了不同功能的公有函數,如圖_1中所示,函數比較細化,便於后期應用的擴展,比較具體是聚類函數:cluster,其中嚴格根據kmeans基本原理,聚類的相似度選用的是最簡單的歐式距離,而迭代的結束判定條件選用兩次中心值之間的偏差是否大於給定Dist_near_zero值。具體參見程序源代碼。
3 數據描述
本次算法實驗采用數據為三維點雲數據,類似於實驗室中三維激光掃描儀器所采得數據,形式上更為簡單,整齊有規律,在cloudcompare中顯示出來,如下圖:
圖4.2 數據原始圖
數據為三維坐標系下的三個點雲集,分別為球體,園面以及正方體,而test.txt文件中是一組三維的點集,是混亂的,聚類算法要做的便是將其中分類存儲起來。很自然的,聚類中K值選擇了3。
在軟件實現時,建立了一個含有結構體類型的容器,對原始數據進行讀取。
typedef struct st_point
{ st_pointxyz pnt; //st_pointxyz 為三維點結構類型數據 stru st_pointxyz
int groupID;
st_point () { }
st_point(st_pointxyz &p, int id)
{pnt = p;
groupID = id;
}
}st_point;
該數據結構類型中包含三維點數據以及所分類的ID,數據容器為vector<st_point>。
4 算法描述與源碼分析
本節重點分析項目中culster聚類函數的具體代碼,由於C++語言較適用於大型程序編寫,本算法又相對簡單,因此未免冗長,具體完整程序見項目源程序。下面只分析Kmeans原理中(2)(3)步驟的程序實現。
如下面程序源代碼:
1 bool KMeans::Cluster() 2 { 3 std::vector<st_pointxyz> v_center(mv_center.size()); 4 5 do 6 { 7 for (int i = 0, pntCount = mv_pntcloud.size(); i < pntCount; ++i) 8 { 9 double min_dist = DBL_MAX; 10 int pnt_grp = 0; 11 for (int j = 0; j < m_k; ++j) 12 { 13 double dist = DistBetweenPoints(mv_pntcloud[i].pnt, mv_center[j]); 14 if (min_dist - dist > 0.000001) 15 { 16 min_dist = dist; 17 pnt_grp = j; 18 } 19 } 20 m_grp_pntcloud[pnt_grp].push_back(st_point(mv_pntcloud[i].pnt, pnt_grp)); 21 } 22 23 //保存上一次迭代的中心點 24 for (size_t i = 0; i < mv_center.size(); ++i) 25 { 26 v_center[i] = mv_center[i]; 27 } 28 29 if (!UpdateGroupCenter(m_grp_pntcloud, mv_center)) 30 { 31 return false; 32 } 33 if (!ExistCenterShift(v_center, mv_center)) 34 { 35 break; 36 } 37 for (int i = 0; i < m_k; ++i){ 38 m_grp_pntcloud[i].clear(); 39 } 40 41 } while (true); 42 43 return true; 44 }
5 算法結果分析
原數據文件test.txt中的數據被分為三類,分別存儲在文件k_1,k_2,k_3中,我們對三個聚類后所得數據點雲進行顏色添加后顯示在cloudcompare上,得下面的顯示圖:
圖4.3 Kmeans聚類結果
上圖是在給定的初始三個聚類中心點為{ 0, 0, 0 },{ 2.5, 2.5, 2.5 },{ 3, 3, -3 }的情況下得到的結果。這是比較理想的,再看下圖:
圖4.4 改變初始聚類中心后的結果
本結果對應的初始三個中心點為{ 2, 2, 2 },{ -2.5, 2.5, 2.5 },{ 3, -3, -3 },很明顯,數據聚類並不理想,這說明K-Means算法一定程度上初始聚類種子點,這個聚類種子點太重要,不同的隨機種子點會有得到完全不同的結果。
上面改動了初始點,下面給出當k=4的聚類結果,分別取了兩組不同的初始點集:
圖4.5.1 k=4聚類結果1
圖4.5.2 k=4聚類結果
由上述聚類結果可知,當k增加時,選取聚類初始點合適,可以得到滿意的結果,如5_1所示,與最初結果相比只是將球點雲聚類成了兩部分,而5_2與5_1相比結果很不理想,由顏色可以看出,圖中只有兩類,另外兩類是空的,說明k值不當,初始值不當的情況下,聚類是會失敗的。
綜上實驗結果分析可以看出,kmeans聚類算法是一類非常快捷的聚類算法,效果也很明顯,局部性較好,容易並行化,對大規模數據集很有意義。但比較依賴於k值得選定與初始聚類中心點的選擇,所以該算法比較適合有人工參與的較大型聚類場合。
工程源碼:http://pan.baidu.com/s/1ntN6Pjb
Kmeans聚類算法 - 開源中國社區 http://www.oschina.net/code/snippet_588162_50491
參考文獻
[1] Hartigan J A, Wong M A. Algorithm AS 136: A k-means clustering algorithm[J]. Applied statistics, 1979: 100-108.