系列文章:數據挖掘算法之決策樹算法 html
k-means算法能夠說是數據挖掘中十大經典算法之一了,屬於無監督的學習。該算法由此衍生出了不少類k-means算法,好比k中心點等等,在數據挖掘領域,不少地方都會用到該算法,他可以把類似的一類很好的聚在一塊兒。一類指的是,他們之間的類似度較高,計算類似度的經常使用度量有歐氏距離、餘弦定理等。本算法採用的是歐式距離度量。這個對理解k-means算法不會形成任何實質性的影響。ios
爲了更好的說明k-means算法是把屬於一類的對象聚成一個簇的,下面貼兩張圖,一張是100個數據對象是,K=2的狀況【圖1】。算法
另一張是1000個數據對象,k=3的狀況,但願你們看完圖可以加深對K-means算法的理解。數據結構
[圖1 objectNum=100 k=2] dom
[圖2 objectNum=1000 k=3]學習
k-means算法的中心思想其實就是迭代,經過不斷的迭代,使聚類效果達到局部最優,爲何咱們說局部最優呢?由於K-means算法的效果的優劣性和最初選取的中心點是有莫大關係的,咱們只能在初始中心點的基礎上達到局部最優解。spa
k-means算法的過程以下:3d
#include<iostream> #include<fstream> #include<vector> #include<random> #include<time.h> #include<string.h>
using namespace std; const int maxNum=0x1<<30; const int repeatMax=100;//控制迭代的上限,這裏主要從效率的角度來考慮。通常來講迭代50--100次就能達到很好的效果
const int AttributeCount=2;//數據屬性維度.
const int ClusterK=8;//聚成的簇的數量
typedef double AttributeType; struct Object{//數據項的數據結構
AttributeType attribute[AttributeCount]; }; vector<Object> allObj;//保存全部的數據
Object cluster[1000][ClusterK];//各個簇的數據項,這裏假定每一個簇的最大量爲1000了,能夠寫成vector的數據結構,
Object oldcenter[ClusterK];//舊的各個中心點
int oldCluObjNum[ClusterK];//舊的各個簇有多少數據量
Object center[ClusterK];//對比舊的中心點
int CluObjNum[ClusterK];//對比舊的各簇的數據量
void getAllobject(ifstream &ifs);//加載全部數據
void kmeans(ifstream &ins);//算法
void produceData(string fileName,int maxNum,int objectNum);//隨機產生數據,fileName文件名,maxNum數據的最大數,objectNum數據個數
int cloestCluster(Object obj);//返回當前數據項與哪一個簇最近
void initCenter();//初始化各中心點
void updateCluster(int cluK,Object obj);//更新簇結構
bool isChange();//判斷迭代以後中心點是否改變,若沒有改變能夠迭代結束了,獲得局部最優解
void copyCenter();//複製到舊的中
void computeCenter();//從新計算中心點
AttributeType Distance(Object obj,Object obj2);//計算兩個點之間的距離
int main(){ //produceData("data2.txt",100,50);
ifstream ifs; ifs.open("data2.txt"); kmeans(ifs); ifs.close(); system("pause"); } void kmeans(ifstream &ins){ getAllobject(ins); initCenter(); for(int i=0;i<ClusterK;i++){ center[i]=allObj[i]; CluObjNum[i]=0; } int repeat=0; while(isChange()&&repeat<repeatMax){//一直迭代,直到中心點再也不改變,或者達到迭代的上限
copyCenter(); for(vector<Object>::iterator begin=allObj.begin();begin<allObj.end();begin++){ int closestK=cloestCluster(*begin); updateCluster(closestK,*begin); } computeCenter(); for(int i=0;i<ClusterK;i++){ cout<<"第"<<i<<"個簇,他們之間的中心點是:"; char file[]={'c','l','u','s','t','e','r',static_cast<char>(i+'0'),'.','t','x','t','\0'}; ofstream out; out.open(file,ifstream::trunc);//輸入到各個簇的文件中保存
for(int l=0;l<AttributeCount;l++){ cout<<center[i].attribute[l]<<" "; } cout<<endl; for(int m=1;m<=CluObjNum[i];m++){ for(int j=0;j<AttributeCount;j++) out<<cluster[m][i].attribute[j]<<" "; out<<endl; } cout<<endl; out.close(); } cout<<endl; repeat++; } } void updateCluster(int cluK,Object obj){//把obj更新到cluK簇中,同時項增長1
cluster[CluObjNum[cluK]+1][cluK]=obj; CluObjNum[cluK]++; } void computeCenter(){ for(int i=0;i<ClusterK;i++){ for(int m=0;m<AttributeCount;m++){ double sum=0; for(int j=0;j<CluObjNum[i];j++){ sum+=cluster[j][i].attribute[m]; } center[i].attribute[m]=sum/CluObjNum[i]; } } } void copyCenter(){ for(int i=0;i<ClusterK;i++){ oldCluObjNum[i]=CluObjNum[i]; CluObjNum[i]=0; for(int j=0;j<AttributeCount;j++){ oldcenter[i].attribute[j]=center[i].attribute[j]; } } } void initCenter(){ Object obj; for(int i=0;i<AttributeCount;i++){ obj.attribute[i]=-1; } for(int i=0;i<ClusterK;i++){ oldcenter[i]=obj; } } int cloestCluster(Object obj){ AttributeType sq=maxNum,m=maxNum; int theCloest=0; for(int i=0;i<ClusterK;i++){ m=Distance(obj,center[i]); if(m<sq){ theCloest=i; sq=m; } } return theCloest; } AttributeType Distance(Object obj,Object obj2){ AttributeType dis=0; for(int i=0;i<AttributeCount;i++){ dis+=(obj.attribute[i]-obj2.attribute[i])*(obj.attribute[i]-obj2.attribute[i]); } return dis; } bool isChange(){ for(int i=0;i<ClusterK;i++){ for(int j=0;j<AttributeCount;j++) if(oldcenter[i].attribute[j]!=center[i].attribute[j]) return true; } return false; } void getAllobject(ifstream &ifs){ while(ifs){ Object obj; for(int i=0;i<AttributeCount;i++) ifs>>obj.attribute[i]; allObj.push_back(obj); } }
如下提供個人一個數據集運行的最終結果:code
版權全部,歡迎轉載,可是轉載請註明出處:瀟一htm