日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Kmeans算法介绍及其实现

發布時間:2025/4/16 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Kmeans算法介绍及其实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


KMeans算法的基本思想是初始隨機給定K個簇中心,按照最鄰近原則把待分類樣本點分到各個簇。然后按平均法重新計算各個簇的質心,從而確定新的簇心。一直迭代,直到簇心的移動距離小于某個給定的值。
?

K-Means聚類算法主要分為三個步驟:
(1)第一步是為待聚類的點尋找聚類中心
(2)第二步是計算每個點到聚類中心的距離,將每個點聚類到離該點最近的聚類中去
(3)第三步是計算每個聚類中所有點的坐標平均值,并將這個平均值作為新的聚類中心
反復執行(2)、(3),直到聚類中心不再進行大范圍移動或者聚類次數達到要求為止

?

下圖展示了對n個樣本點進行K-means聚類的效果,這里k取2:
(a)未聚類的初始點集
(b)隨機選取兩個點作為聚類中心
(c)計算每個點到聚類中心的距離,并聚類到離該點最近的聚類中去
(d)計算每個聚類中所有點的坐標平均值,并將這個平均值作為新的聚類中心
(e)重復(c),計算每個點到聚類中心的距離,并聚類到離該點最近的聚類中去
(f)重復(d),計算每個聚類中所有點的坐標平均值,并將這個平均值作為新的聚類中心

%隨機獲取150個點 X = [randn(50,2)+ones(50,2);randn(50,2)-ones(50,2);randn(50,2)+[ones(50,1),-ones(50,1)]];opts = statset('Display','final');%調用Kmeans函數 %X N*P的數據矩陣 %Idx N*1的向量,存儲的是每個點的聚類標號 %Ctrs K*P的矩陣,存儲的是K個聚類質心位置 %SumD 1*K的和向量,存儲的是類間所有點與該類質心點距離之和 %D N*K的矩陣,存儲的是每個點與所有質心的距離;[Idx,Ctrs,SumD,D] = kmeans(X,3,'Replicates',3,'Options',opts);%畫出聚類為1的點。X(Idx==1,1),為第一類的樣本的第一個坐標;X(Idx==1,2)為第二類的樣本的第二個坐標 plot(X(Idx==1,1),X(Idx==1,2),'r.','MarkerSize',14) hold on plot(X(Idx==2,1),X(Idx==2,2),'b.','MarkerSize',14) hold on plot(X(Idx==3,1),X(Idx==3,2),'g.','MarkerSize',14)%繪出聚類中心點,kx表示是圓形 plot(Ctrs(:,1),Ctrs(:,2),'kx','MarkerSize',14,'LineWidth',4) plot(Ctrs(:,1),Ctrs(:,2),'kx','MarkerSize',14,'LineWidth',4) plot(Ctrs(:,1),Ctrs(:,2),'kx','MarkerSize',14,'LineWidth',4)legend('Cluster 1','Cluster 2','Cluster 3','Centroids','Location','NW')

#include <iostream> #include <sstream> #include <fstream> #include <vector> #include <math.h> #include <stdlib.h> #define k 3//簇的數目 using namespace std; //存放元組的屬性信息 typedef vector<double> Tuple;//存儲每條數據記錄int dataNum;//數據集中數據記錄數目 int dimNum;//每條記錄的維數//計算兩個元組間的歐幾里距離 double getDistXY(const Tuple& t1, const Tuple& t2) {double sum = 0;for(int i=1; i<=dimNum; ++i){sum += (t1[i]-t2[i]) * (t1[i]-t2[i]);}return sqrt(sum); }//根據質心,決定當前元組屬于哪個簇 int clusterOfTuple(Tuple means[],const Tuple& tuple){double dist=getDistXY(means[0],tuple);double tmp;int label=0;//標示屬于哪一個簇for(int i=1;i<k;i++){tmp=getDistXY(means[i],tuple);if(tmp<dist) {dist=tmp;label=i;}}return label; } //獲得給定簇集的平方誤差 double getVar(vector<Tuple> clusters[],Tuple means[]){double var = 0;for (int i = 0; i < k; i++){vector<Tuple> t = clusters[i];for (int j = 0; j< t.size(); j++){var += getDistXY(t[j],means[i]);}}//cout<<"sum:"<<sum<<endl;return var;} //獲得當前簇的均值(質心) Tuple getMeans(const vector<Tuple>& cluster){int num = cluster.size();Tuple t(dimNum+1, 0);for (int i = 0; i < num; i++){for(int j=1; j<=dimNum; ++j){t[j] += cluster[i][j];}}for(int j=1; j<=dimNum; ++j)t[j] /= num;return t;//cout<<"sum:"<<sum<<endl; }void print(const vector<Tuple> clusters[]) {for(int lable=0; lable<k; lable++){cout<<"第"<<lable+1<<"個簇:"<<endl;vector<Tuple> t = clusters[lable];for(int i=0; i<t.size(); i++){cout<<i+1<<".(";for(int j=0; j<=dimNum; ++j){cout<<t[i][j]<<", ";}cout<<")\n";}} }void KMeans(vector<Tuple>& tuples){vector<Tuple> clusters[k];//k個簇Tuple means[k];//k個中心點int i=0;//一開始隨機選取k條記錄的值作為k個簇的質心(均值)srand((unsigned int)time(NULL));for(i=0;i<k;){int iToSelect = rand()%tuples.size();if(means[iToSelect].size() == 0){for(int j=0; j<=dimNum; ++j){means[i].push_back(tuples[iToSelect][j]);}++i;}}int lable=0;//根據默認的質心給簇賦值for(i=0;i!=tuples.size();++i){lable=clusterOfTuple(means,tuples[i]);clusters[lable].push_back(tuples[i]);}double oldVar=-1;double newVar=getVar(clusters,means);cout<<"初始的的整體誤差平方和為:"<<newVar<<endl; int t = 0;while(abs(newVar - oldVar) >= 1) //當新舊函數值相差不到1即準則函數值不發生明顯變化時,算法終止{cout<<"第 "<<++t<<" 次迭代開始:"<<endl;for (i = 0; i < k; i++) //更新每個簇的中心點{means[i] = getMeans(clusters[i]);}oldVar = newVar;newVar = getVar(clusters,means); //計算新的準則函數值for (i = 0; i < k; i++) //清空每個簇{clusters[i].clear();}//根據新的質心獲得新的簇for(i=0; i!=tuples.size(); ++i){lable=clusterOfTuple(means,tuples[i]);clusters[lable].push_back(tuples[i]);}cout<<"此次迭代之后的整體誤差平方和為:"<<newVar<<endl; }cout<<"The result is:\n";print(clusters); } int main(){char fname[256];cout<<"請輸入存放數據的文件名: ";cin>>fname;cout<<endl<<" 請依次輸入: 維數 樣本數目"<<endl;cout<<endl<<" 維數dimNum: ";cin>>dimNum;cout<<endl<<" 樣本數目dataNum: ";cin>>dataNum;ifstream infile(fname);if(!infile){cout<<"不能打開輸入的文件"<<fname<<endl;return 0;}vector<Tuple> tuples;//從文件流中讀入數據for(int i=0; i<dataNum && !infile.eof(); ++i){string str;getline(infile, str);istringstream istr(str);Tuple tuple(dimNum+1, 0);//第一個位置存放記錄編號,第2到dimNum+1個位置存放實際元素tuple[0] = i+1;for(int j=1; j<=dimNum; ++j){istr>>tuple[j];}tuples.push_back(tuple);}cout<<endl<<"開始聚類"<<endl;KMeans(tuples);return 0; }


總結

以上是生活随笔為你收集整理的Kmeans算法介绍及其实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。