聚类算法--近邻聚类算法(C++实现)
生活随笔
收集整理的這篇文章主要介紹了
聚类算法--近邻聚类算法(C++实现)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
聚類算法–近鄰聚類算法(C++實現)
寫在前面:
? 最近鄰聚類算法,應該不是KNN,也不是K-means,就是一個特別基礎的算法,但是在CSDN沒有找到C++實現的這個算法,只有一個python寫的(https://blog.csdn.net/Ha_hha/article/details/79128777),于是自己寫了一個,目前還有錯誤,相同數據多次運行的結果不一樣,希望有大佬可以指出是哪里有問題
算法介紹:
代碼介紹:
用的vector存放內容,sampoint 存放樣本點,clucenter存放聚類中心點。
在測試版輸入樣本點有兩中方式,一個是樣本點隨機生成,一個是自己輸入。
第一個聚類中心點隨機生成。
euclidean_clu函數用來計算樣本點和當前已有的聚類中心的歐式距離,如果樣本點和每個聚類中心的距離都大于閾值T,就增加新的聚類中心,同時退出當前循環,重新執行當前函數。當該函數執行完,說明已經找到了全部的聚類中心。
euclidean_step再次計算所有樣本點和聚類中心點的距離,找到距離樣本點最近的一個聚類中心,進行分類,這里用了map存放。同時該函數輸出最后的結果。
代碼(純凈版):
#include <bits/stdc++.h> using namespace std;vector<vector<long long >> sampoint; vector<vector<long long >> clucenter; long long n,v,T,random_num;void euclidean_clu(); void append_clu(long long x); void euclidean_step(); int main(){/*1.輸入數據*/long long temp;cout<<"輸入樣本個數和維度:"<<endl;cin>>n>>v; //輸入樣本個數和維度 cout<<"輸入閾值T:"<<endl;cin>>T;vector<long long > intemp_clu;long long temp_n=n;cout<<"隨機生成的樣本點如下:"<<endl;while(n--){for(long long i=0;i<v;i++){temp=rand()%100;intemp_clu.push_back(temp);}sampoint.push_back(intemp_clu);intemp_clu.clear(); //每次輸入完成都要清空,否則之前的數據會保留 }n=temp_n;/*輸出測試*/for(long long i=0;i<temp_n;i++){for(long long j=0;j<v;j++){cout<<sampoint[i][j]<<" ";}cout<<endl;}/*2.獲取第一個聚類中心,并在樣本點中刪除聚類中心*/long long temp_random;vector<long long > first_clucenter;temp_random=rand()%sampoint.size();for(long long i=0;i<v;i++){first_clucenter.push_back(sampoint[temp_random][i]);} sampoint.erase(sampoint.begin()+temp_random);clucenter.push_back(first_clucenter);cout<<endl;euclidean_clu();euclidean_step();} void euclidean_clu(){for(long long i=0;i<sampoint.size();i++){long long temp_dean=0,min_dean=1000000,min_clu=0,min_sam;for(long long j=0;j<clucenter.size();j++){for(long long k=0;k<v;k++){ temp_dean+=pow((sampoint[i][k]-clucenter[j][k]),2);}temp_dean=sqrt(temp_dean);if(temp_dean>T){ append_clu(i);euclidean_clu(); //加入新的中心點后重新進行歐氏距離的計算 } temp_dean=0; } } return ; }/*4.增加聚類中心點*/ void append_clu(long long x){clucenter.push_back(sampoint[x]);sampoint.erase(sampoint.begin()+x); } /*對樣本點根據已有的聚類中心進行劃分*/ void euclidean_step(){long long temp_dean=0,min_dean=1000000,min_clu=0;map<long long ,long long > pdean;for(long long i=0;i<sampoint.size();i++){temp_dean=0,min_dean=1000000,min_clu=0;for(long long j=0;j<clucenter.size();j++){for(long long k=0;k<v;k++){ temp_dean+=pow((sampoint[i][k]-clucenter[j][k]),2);}if(temp_dean<min_dean){ //取最小的距離和對應的聚類中心 min_dean=temp_dean;min_clu=j;} temp_dean=0;}pdean.insert({i,min_clu});}cout<<"總共有"<<clucenter.size()<<"個聚類中心:"<<endl;for(long long i=0;i<clucenter.size();i++){for(long long j=0;j<v;j++){cout<<clucenter[i][j]<<" ";}cout<<endl;}cout<<endl;for(long long i=0;i<clucenter.size();i++){cout<<"第"<<i+1<<"類樣本點:"<<endl;cout<<"(";for(long long j=0;j<v;j++){cout<<clucenter[i][j]<<" ";}cout<<")";cout<<endl;for(auto it=pdean.begin();it!=pdean.end();it++){if((*it).second==i){cout<<"(";for(long long j=0;j<v;j++){cout<<sampoint[(*it).first][j]<<" ";}cout<<") ";}}cout<<endl;}}代碼(測試用):
#include <bits/stdc++.h> using namespace std;vector<vector<long long>> sampoint; vector<vector<long long>> clucenter; long long n,v,T,random_num;void euclidean_clu(); void append_clu(long long x); void euclidean_step(); int main(){/*1.輸入數據*/long long temp;cout<<"輸入樣本個數和維度:"<<endl;cin>>n>>v; //輸入樣本個數和維度 cout<<"輸入閾值T:"<<endl;cin>>T;vector<long long> intemp_clu;long long temp_n=n;cout<<"隨機生成的樣本點如下:"<<endl;while(n--){for(long long i=0;i<v;i++){// cin>>temp;temp=rand()%100;intemp_clu.push_back(temp);//cout<<long longemp_clu[long longemp_clu.size()-1]<<endl;}sampoint.push_back(intemp_clu);intemp_clu.clear(); //每次輸入完成都要清空,否則之前的數據會保留 }n=temp_n;/*輸出測試*/for(long long i=0;i<temp_n;i++){for(long long j=0;j<v;j++){cout<<sampoint[i][j]<<" ";}cout<<endl;}/*2.獲取第一個聚類中心,并在樣本點中刪除聚類中心*/long long temp_random;vector<long long> first_clucenter;temp_random=rand()%sampoint.size();//cout<<temp_random<<endl;for(long long i=0;i<v;i++){first_clucenter.push_back(sampoint[temp_random][i]);} sampoint.erase(sampoint.begin()+temp_random);clucenter.push_back(first_clucenter);cout<<"生成的第一個聚類中心點是:"<<endl;for(long long i=0;i<v;i++){cout<<clucenter[0][i]<<" ";}cout<<endl;/*first_clucenter.clear(); //測試是否成功刪除聚點的樣本點 for(long long i=0;i<temp_n;i++){for(long long j=0;j<v;j++){cout<<sampoint[i][j]<<" ";}cout<<endl;}*/euclidean_clu();cout<<"over"<<endl;euclidean_step();//std::cout << "The run time is: " <<(double)clock() / CLOCKS_PER_SEC << "s" << std::endl;//printf("Time used = %.2f\n", (double)clock() / CLOCKS_PER_SEC); }/*3.計算各樣本點到聚類中心的歐式距離,函數實現*/ void euclidean_clu(){vector<long long> all_dean; // cout<<sampoint.size()<<endl; /*輸出樣本點的個數*/long long temp_x=0;for(long long i=0;i<sampoint.size();i++){long long temp_dean=0,min_dean=1000000,min_clu=0,min_sam;for(long long j=0;j<clucenter.size();j++){for(long long k=0;k<v;k++){ temp_dean+=(sampoint[i][k]-clucenter[j][k])*(sampoint[i][k]-clucenter[j][k]);}/*得到樣本點和某聚類中心點的距離之后,判斷是否大于閾值,如果大于,則成為新的聚類中心點*/// cout<<temp_dean<<" "<<i<<" "<<j<<endl; //輸出各個樣本點和聚類中心的歐氏距離 temp_x=sqrt(temp_dean);temp_dean=0;// cout<<"temp_x:"<<temp_x<<endl;all_dean.push_back(temp_x);/* if(long long(sqrt(temp_dean))>T){cout<<j<<endl;cout<<temp_dean<<" "<<long long(sqrt(temp_dean))<<" "<<i<<" "<<j<<endl; //cout<<"出現新的聚類中心"<<endl; append_clu(i);*/ //測試用 /*for(long long i=0;i<sampoint.size();i++){for(long long j=0;j<v;j++){cout<<sampoint[i][j]<<" ";}cout<<endl;}*/// euclidean_clu(); //加入新的中心點后重新進行歐氏距離的計算// return ; } bool bool_clu=true;for(long long a=0;a<all_dean.size();a++){// cout<<all_dean[i]<<" ";if(all_dean[i]<T){bool_clu=false;break;}}all_dean.clear();if(bool_clu){//cout<<"出現新的聚類中心"<<endl; append_clu(i);euclidean_clu(); //加入新的中心點后重新進行歐氏距離的計算return ; }//cout<<temp_dean<<endl; /* if(temp_dean<min_dean){ //取最小的距離和對應的聚類中心 min_dean=temp_dean;min_clu=j;}temp_dean=0; }cout<<i<<" "<<min_clu<<" "<<" "<<min_dean<<endl;pdean.insert({i,min_clu});}return ; } */ } return ; }/*4.增加聚類中心點*/ void append_clu(long long x){clucenter.push_back(sampoint[x]); /* cout<<"加入新的聚類中心:";for(long long i=0;i<v;i++){cout<<sampoint[x][i]<<" ";} */ // cout<<"加入了新的聚類中心"<<endl;if(x==sampoint.size()-1){sampoint.pop_back();// cout<<"最后一個"<<endl;}else{sampoint.erase(sampoint.begin()+x);}return ;} /*對樣本點根據已有的聚類中心進行劃分*/ void euclidean_step(){/* 測試用cout<<"聚類中心點為:"<<endl;for(long long i=0;i<clucenter.size();i++){for(long long j=0;j<v;j++){cout<<clucenter[i][j]<<" ";}cout<<endl;} *//* cout<<endl;for(long long i=0;i<sampoint.size();i++){for(long long j=0;j<v;j++){cout<<sampoint[i][j]<<" ";}cout<<endl;}*/long long temp_dean=0,min_dean=10000,min_clu=0;map<long long,long long> pdean;for(long long i=0;i<sampoint.size();i++){temp_dean=0,min_dean=10000,min_clu=0;for(long long j=0;j<clucenter.size();j++){for(long long k=0;k<v;k++){ temp_dean+=pow((sampoint[i][k]-clucenter[j][k]),2);}//cout<<temp_dean<<endl;if(temp_dean<min_dean){ //取最小的距離和對應的聚類中心 min_dean=temp_dean;min_clu=j;} //cout<<i<<" "<<min_clu<<" "<<" "<<min_dean<<endl;temp_dean=0;}pdean.insert({i,min_clu});}/*for(auto it=pdean.begin();it!=pdean.end();it++){cout<<(*it).first<<" "<<(*it).second<<endl;}*/cout<<"總共有"<<clucenter.size()<<"個聚類中心:"<<endl;for(long long i=0;i<clucenter.size();i++){for(long long j=0;j<v;j++){cout<<clucenter[i][j]<<" ";}cout<<endl;}cout<<endl;for(long long i=0;i<clucenter.size();i++){cout<<"第"<<i+1<<"類樣本點:";cout<<"{";cout<<"(";for(long long j=0;j<v;j++){cout<<clucenter[i][j]<<" ";}cout<<")"; // cout<<endl;for(auto it=pdean.begin();it!=pdean.end();it++){if((*it).second==i){cout<<"(";for(long long j=0;j<v;j++){cout<<sampoint[(*it).first][j]<<" ";}cout<<") ";}}cout<<"}"; // cout<<endl;}}寫在最后:
ldu模式識別,代碼僅作學習參考使用,🈲抄襲🙅?,而且最后結果還是有錯的。
總結
以上是生活随笔為你收集整理的聚类算法--近邻聚类算法(C++实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html特殊字符表和颜色代码表
- 下一篇: C/C++百行代码实现热门游戏-消消乐