K means聚類演算法原理及c 實現

2021-10-01 23:10:45 字數 3183 閱讀 5161

聚類是指根據資料本身的特徵對資料進行分類,不需要人工標註,是無監督學習的一種。k-means演算法是聚類演算法中最簡單的演算法之一。

k-means 演算法將n個資料物件劃分為 k個聚類以便使得所獲得的聚類滿足:同一聚類中的物件相似度較高;而不同聚類中的物件相似度較小。聚類相似度是利用各聚類中物件的均值所獲得乙個「中心物件」(引力中心)來進行計算的。

基於這樣乙個假設,我們再來匯出k-means所要優化的目標函式:設我們一共有n個資料點需要分為k個cluster,而k-means要做的就是要最小化這個目標函式

過程如下:

1.首先從n個資料物件任意選擇 k 個物件作為初始聚類中心;而對於所剩下其它物件,則根據它們與這些聚類中心的相似度(距離),分別將它們分配給與其最相似的(聚類中心所代表的)聚類;

2.然後再計算每個所獲新聚類的聚類中心(該聚類中所有物件的均值

);不斷重複這一過程直到標準測度函式開始收斂為止。

一般都採用均方差作為標準測度函式,k個聚類具有以下特點:各聚類本身盡可能的緊湊,而各聚類之間盡可能的分開。

每一次更新聚類中心都會使目標函式減小,因此迭代最終j會達到乙個極小值,不能保證是全域性最小值。k-means對於雜訊十分敏感。

c++實現:

class clustermethod

;

類內函式實現:

//param@v 儲存分類結果 v[i][j][k]表示第i類第j個資料第k個特徵(從0開始)

//param@feateres 輸入資料 feateres[i][j]表示第i個資料第j個特徵(i,j從0開始)

//param@clusternum 分類數

//param@samplenum 資料數量

//param@featurenum 資料特徵數

void clustermethod::getclusterd(vector> >&v, double** feateres, int clusternum, int samplenum, int featurenum)

//類內資料初始化

void clustermethod::initialize(double** feateres, int clusternum, int samplenum, int featurenum)

pdistances = new double*[msamplenum];

for (int i = 0; i < msamplenum; ++i)

clusterresult = new int[msamplenum];

}//演算法入口

void clustermethod::k_means(vector> >&v)

//初始化聚類中心

void clustermethod::k_means_initialize()

}}

上面初始化聚類中心是令資料前i(i為聚類中心個數)個點為i個聚類中心。(注意一定不能使用mpcenters[i] = mpsample[i]進行初始化,它們是指標。)

也可以隨機選取i個資料令為聚類中心,這樣同樣的資料多次的執行結果就可能不同。因為k-means結果不一定達到全域性最小點,最簡單的解決方法就是多次執行(這裡指整個函式的重複執行,與聚類時的迭代次數不同)取目標函式最小時候的聚類結果。如果像前面那種每次都選前i個資料初始化聚類中心,多次執行將不能解決區域性最小點問題。

聚類和更新聚類中心的實現如下:

//聚類過程

void clustermethod::k_means_calculate(vector> >&v)

} //計算歐式距離

for (int i = 0; i < msamplenum; ++i)

now_j += pdistances[i][j];}}

if (j - now_j < 0.01)//目標函式不再變化結束迴圈

j = now_j;

//a存放臨時分類結果

vector> > a(mclusternum);

for (int i = 0; i < msamplenum; ++i)

}vectorvec(mfeaturenum);

for (int k = 0; k < mfeaturenum; ++k)

a[clusterresult[i]].push_back(vec);

// v[clusterresult[i]].push_back(vec);這裡不能這樣給v輸入資料,因為v沒有初始化大小

} v = a;

//計算新的聚類中心

for (int j = 0; j < mclusternum; ++j)

}for (int j = 0; j < mclusternum; ++j)

if (v[j].size() != 0)

}} }

//輸出聚類中心

for (int j = 0; j < mclusternum; ++j)

cout << endl;

}}

生成隨機資料函式:

//param@datanum 資料數量

//param@featurenum 每個資料特徵數

double** createdata(int datanum, int featurenum)

cout << "輸入資料:" << endl;

for (int i = 0; i < datanum ; ++i)

cout << endl;

} return data;

}

主函式:

int main()

cout << endl;

} }}

執行結果如下:

k-means更新聚類中心時使用每類的均值,因此對雜訊較為敏感。

k-medoids將前面的均值改為中位數,這樣可以避免個別過大或過小的點對聚類中心的影響。

說到中位數,我就想起了唐僧師徒。。。不對,想起了之前寫的選擇演算法,不需要對所有資料進行排序,執行速度更快。

但這也不是說k-medoids就一定比k-means好,要知道,資料量較大時,演算法的時間也是關鍵。求均值所需時間比求中位數小。因此,孰優孰劣需要看具體需求。

K Means聚類演算法原理

k means演算法是無監督的聚類演算法,它實現起來比較簡單,聚類效果也不錯,因此應用很廣泛。k means演算法有大量的變體,本文就從最傳統的k means演算法講起,在其基礎上講述k means的優化變體方法。包括初始化優化k means 距離計算優化elkan k means演算法和大資料情況...

K Means聚類演算法原理

k means演算法是無監督的聚類演算法,它實現起來比較簡單,聚類效果也不錯,因此應用很廣泛。k means演算法有大量的變體,本文就從最傳統的k means演算法講起,在其基礎上講述k means的優化變體方法。包括初始化優化k means 距離計算優化elkan k means演算法和大資料情況...

K Means聚類演算法的原理及實現

1 如何理解k means演算法?2 如何尋找k值及初始質心?3 如何應用k means演算法處理資料?k means是聚類演算法中的一種,其中k表示類別數,means表示均值。顧名思義k means是一種通過均值對資料點進行聚類的演算法。k means演算法通過預先設定的k值及每個類別的初始質心對...