系列文章:數據挖掘算法之決策樹算法
k-means算法可以說是數據挖掘中十大經典算法之一了,屬於無監督的學習。該算法由此衍生出了很多類k-means算法,比如k中心點等等,在數據挖掘領域,很多地方都會用到該算法,他能夠把相似的一類很好的聚在一起。一類指的是,他們之間的相似度較高,計算相似度的常用度量有歐氏距離、余弦定理等。本算法采用的是歐式距離度量。這個對理解k-means算法不會造成任何實質性的影響。
為了更好的說明k-means算法是把屬於一類的對象聚成一個簇的,下面貼兩張圖,一張是100個數據對象是,K=2的情況【圖1】。
另外一張是1000個數據對象,k=3的情況,希望大家看完圖能夠加深對K-means算法的理解。
[圖1 objectNum=100 k=2]
[圖2 objectNum=1000 k=3]
k-means算法的中心思想其實就是迭代,通過不斷的迭代,使聚類效果達到局部最優,為什么我們說局部最優呢?因為K-means算法的效果的優劣性和最初選取的中心點是有莫大關系的,我們只能在初始中心點的基礎上達到局部最優解。
k-means算法的過程如下:
2)對剩余的每個文檔測量其到每個質心的距離,並把它歸到最近的質心的類
3)重新計算已經得到的各個類的質心
4)迭代2~3步直至新的質心與原質心相等或小於指定閾值(我們這里實際上用迭代次數代替了閾值的功能),算法結束
輸入: 一個數據集dataset,類個數k
輸出:k個小的數據集,也就是K個類。
該算法會有一些缺點主要是:
1、計算量大,不斷的迭代,不斷的計算,計算量大事在所難免了。
2、K值的指定也是一個難點,很多時候我們並不知道k是多少?
3、只能得到局部最優解,這一點我們在前面已經討論過了。
算法能夠一行行讀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); } }
以下提供我的一個數據集運行的最終結果:
版權所有,歡迎轉載,但是轉載請注明出處:瀟一