數據挖掘算法之k-means算法

     系列文章:數據挖掘算法之決策樹算法   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

1)從N個文檔隨機選取K個文檔做爲質心(即中心點)
2)對剩餘的每一個文檔測量其到每一個質心的距離,並把它歸到最近的質心的類
3)從新計算已經獲得的各個類的質心
4)迭代2~3步直至新的質心與原質心相等或小於指定閾值(咱們這裏實際上用迭代次數代替了閾值的功能),算法結束
輸入: 一個數據集dataset,類個數k
          輸出:k個小的數據集,也就是K個類。
 該算法會有一些缺點主要是:
    一、計算量大,不斷的迭代,不斷的計算,計算量大事在所不免了。
    二、K值的指定也是一個難點,不少時候咱們並不知道k是多少?
    三、只能獲得局部最優解,這一點咱們在前面已經討論過了。
    算法可以一行行讀txt數據,固然其餘格式數據也是能夠的,稍微改動下便可。至關方便實用。本着開源的方式,附上90%代碼:void produceData(string fileName,int maxNum,int objectNum);方法代碼沒有附上,該方法用來產生隨機數據。若是須要所有源代碼請點贊後留下email地址,我將會在第一時間發到你郵箱,不便之處敬請原諒,畢竟寫一篇文章也不是那麼容易,我只是想看看到底能幫助到多少人,謝謝理解!
   
#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

相關文章
相關標籤/搜索