• 数据挖掘之K-Means算法


    /*
    K-Means思想: 将n个样本分成k个聚类,每个聚类里的样本关联性(或者说是相似性)比较高。
    举个例子,假如有5个样本,每个样本是一个2维向量,分别记做A,B,C,D,E,我要将他们分成2个聚类,第一步是随机选2个样本(也可以是虚拟的)把它们当做中心点,然后将
    A,B,C,D,E归类到距离最小的那个中心点,之后再对每个聚类进行调整中心点,假如现在A,B,C是一个聚类,D,E是一个聚类,调整的方式的话,以A,B,C这个聚类为例,
    那么中心点的第一维取A,B,C的第一维的平均值,第二维也是取平均值。于是得到了新的聚类中心点,一直迭代下去,直到所有的中心点不发生变化。
    */
    #include<iostream> #include<fstream> #include<cmath> #include<cstdlib> #include<ctime> using namespace std; struct Vector //数据向量 { double *coords; int size; Vector():coords(NULL),size(0){} Vector(int d){ create(d); } void create(int d) { size=d; coords=new double[size]; for(int i=0;i<size;i++) coords[i]=0.0; } void copy(const Vector& other) { if(size==0) create(other.size); for(int i=0;i<size;i++) coords[i]=other.coords[i]; } void add(const Vector& other) { for(int i=0;i<size;i++) coords[i]+=other.coords[i]; } ~Vector() { if(coords) delete[] coords; size=0; } }; struct Cluster //聚类结构 { Vector center; //中心 int *member; //各个数据的索引 int memberNum; //成员个数 }; class KMeans { private: int num; //数据个数 int dimen; //维度数 int clusterNum; //聚类数 Vector *observations; //数组 Cluster *clusters; //聚类数组 int passNum; //迭代次数 public: KMeans(int n,int d,int k,Vector *ob) :num(n),dimen(d),clusterNum(k),observations(ob), clusters(new Cluster[k]){ for(int x=0;x<clusterNum;x++) clusters[x].member=new int[n]; } ~KMeans(){ for(int k=0;k<clusterNum;k++) delete []clusters[k].member; delete []clusters; } void initClusters(){ for(int i=0;i<clusterNum;i++){ clusters[i].member[0]=i; clusters[i].center.copy(observations[i]); //该数据作为数据中心 } } void run(){ bool converged=false; //用于判断是否收敛 passNum=0; //迭代次数 while(!converged&&passNum<999){ distribute(); //将数据分配到聚中心最近的聚类。 converged=recalculateCenters(); //计算新的聚类中心,并确认是否已经收敛 passNum++; } } void distribute(){ for(int k=0;k<clusterNum;k++) getCluster(k).memberNum=0; //清零 for(int i=0;i<num;i++){ Cluster& cluster=getCluster(closestCluster(i)); //找到最接近的其中心的聚类 int memID=cluster.memberNum; //把数据i添加到该聚类中 cluster.member[memID]=i; cluster.memberNum++; } } int closestCluster(int id){ int clusterID=0; //假定索引为id的数据最接近第一个聚类 double minDist=eucNorm(id,0); //计算到第一个聚类中心的误差(用距离的平方和作为误差) for(int k=1;k<clusterNum;k++) { double d=eucNorm(id,k); if(d<minDist){ //更新最小值 minDist=d; clusterID=k; } } return clusterID; } double eucNorm(int id,int k){ Vector& observ=observations[id]; Vector& center=clusters[k].center; double sumOfSquare=0; for(int d=0;d<dimen;d++){ double dist=observ.coords[d]-center.coords[d]; sumOfSquare+=dist*dist; } return sumOfSquare; } bool recalculateCenters(){ //重新计算聚类中心 bool converged=true; for(int k=0;k<clusterNum;k++){ Cluster& cluster=getCluster(k); Vector average(dimen); for(int m=0;m<cluster.memberNum;m++) average.add(observations[cluster.member[m]]); for(int d=0;d<dimen;d++){ average.coords[d]/=cluster.memberNum; if(average.coords[d]!=cluster.center.coords[d]){ //如果和原来的聚类中心不同表示没有收敛 converged=false; //置为false cluster.center.coords[d]=average.coords[d]; //用平均值作为的新的聚类中心 } } } return converged; } //获得第id个聚类 Cluster& getCluster(int id){ return clusters[id]; } }; //打印一个数据 void printVector(ostream& output,const Vector& v){ for(int i=0;i<v.size;i++){ if(i!=0) output<<","; output<<v.coords[i]; } } void partitionObservations(istream& input){ int n,dimen,k;//n个数据,dimen维,k个簇 input>>n>>dimen>>k; //输入 Vector *obs=new Vector[n]; //n个向量点 for(int i=0;i<n;i++){ obs[i].create(dimen); //初始化 for(int d=0;d<dimen;d++) input>>obs[i].coords[d]; } //创建KMeans实例 KMeans kmeans(n,dimen,k,obs); kmeans.initClusters(); kmeans.run(); ostream& output=cout; for(int c=0;c<k;c++){ //输出k个簇 Cluster& cluster=kmeans.getCluster(c); output<<"----第"<<(c+1)<<"个聚类---- "; output<<"聚类中心:"; printVector(output,cluster.center); for(int m=0;m<cluster.memberNum;m++){ int id=cluster.member[m]; //存储的都是id printVector(output,obs[id]); output<<" "; } output<<endl; } delete[] obs; } int main(){ /* const char *fileName="observations.txt"; ifstream obIn(fileName); if(obIn.is_open()) partitionObservations(obIn); else cout<<"open"<<fileName<<" is fail!"<<endl; */ return 0; }
  • 相关阅读:
    Android Animations动画使用详解
    android LinearLayout和RelativeLayout实现精确布局
    中国天气网API
    获取中央气象台API 完整城市列表简单方式
    Django框架 连接Oracle -ServerName方式报错
    关于java的动态代理
    Mybatis缓存
    Git使用,将本地项目推送到GitHub上
    使用doxc4j将word转pdf遇到的一个问题
    linux安装jdk
  • 原文地址:https://www.cnblogs.com/wust-ouyangli/p/6571888.html
Copyright © 2020-2023  润新知