DM&ML_note.6-K-中心点聚类算法
来源:互联网 发布:linux rpm文件 编辑:程序博客网 时间:2024/06/05 02:24
这个学期要学DM&ML,用的是《数据挖掘算法原理与实现》王振武 本着造福同学的思想,开一个DM&ML的笔记系列,打算给书上的源代码添加一点注释,方便阅读和理解
- 前置知识要求
- 具体实现
- 感想
前置知识要求
C++,队列
具体实现
#include "iostream"#include "time.h"using namespace std;struct mem //成员结构体包含符号和一个表示是否是中心点的属性{ bool isMedoid; char symbol;};struct Node; //队列节点typedef struct Node * PNode; //队列节点指针struct Node //队列节点结构体{ mem info; PNode link;};struct LinkQueue{ //队列数据结构 PNode f;//hiro:队列头 PNode r;//hiro:队列尾};typedef struct LinkQueue * PLinkQueue; //队列指针PLinkQueue createEmptyQueue_link() //创建空队列函数{ PLinkQueue plqu; plqu=(PLinkQueue)malloc(sizeof(struct LinkQueue)); if(plqu!=NULL) { plqu->f=NULL; plqu->r=NULL; } else cout<<"Out of space!"<<endl; return plqu;}int isEmptyQueue_link(PLinkQueue plqu) //判断队列是否为空函数{ return (plqu->f==NULL);}void enQueue_Link(PLinkQueue plqu, mem x) //元素入队函数{ PNode p; p=(PNode)malloc(sizeof(struct Node)); if(p==NULL)cout<<"Out of space!"<<endl; else { p->info=x; p->link=NULL; if(plqu->f==NULL) plqu->f=p; else plqu->r->link=p; plqu->r=p; }}void deQueue_link(PLinkQueue plqu) //队列元素出队并打印函数{ PNode p; if(plqu->f==NULL)cout<<"Empty Queue"<<endl; else { p=plqu->f; cout<<p->info.symbol; plqu->f=p->link; free(p); }}void showQueue(PLinkQueue pq) //打印出队列并释放队列占用内存空间{ cout << "{"; while (!isEmptyQueue_link(pq)) { deQueue_link(pq); cout << ","; } cout << '\b'; cout << "}" << endl;}/*hiro:以上所有函数,结构体为队列数据结构及相关操作的实现,可以跳过阅读。完全可以用stl代替,不过也写得没什么问题*//*hiro:真的就只是打印,可跳过*/void showCase(double linjiebiao[5][5]) //打印邻接矩阵函数{ int i,j; char tmp; cout<<"目前的邻接矩阵形式如下:"<<endl; cout<<"=========================================="<<endl; cout<<" A B C D E "<<endl; for(i=0;i<5;i++) { switch (i) { case 0: tmp='A';break; case 1: tmp='B';break; case 2: tmp='C';break; case 3: tmp='D';break; case 4: tmp='E';break; } cout<<tmp; for(j=0;j<5;j++) cout<<" "<<linjiebiao[i][j]; cout<<endl; } cout<<"=========================================="<<endl;}/*hiro:真的就只是生成了两个不想等的随机数然后赋值。。。*/void arbStart(struct mem memlist[5]) //起初时随机确定两个为中心点{ int i,j; for(i=0;i<5;i++) if(memlist[i].isMedoid!=false) memlist[i].isMedoid=false; srand((unsigned)time(NULL)); i = rand()%5; memlist[i].isMedoid=true; j= rand()%5; while(j==i) { j= rand()%5; } memlist[j].isMedoid=true;}double distance(int j, int i, int k, double linjiebiao[5][5]) //求解点ji、k两个中心点中较近的那个点的距离,参考邻接矩阵linjiebiao { if(linjiebiao[j][i]<linjiebiao[j][k]) return linjiebiao[j][i]; else return linjiebiao[j][k];}//求中心点i和h交换后 距离代价TC 的变化值double TC(int index[2],int i,int h, double linjiebiao[5][5]) { int j; double sum=0; int tmp;/*hiro:tmp==另一个中心点对应的下标*/ if(i==index[0]) tmp=index[1]; else if(i==index[1]) tmp=index[0]; for(j=0;j<5;j++) { /*hiro: distance(j,h,tmp,linjiebiao)替换后的距离 distance(j, index[0], index[1],linjiebiao)原本的距离 这一条公式直接囊括了四种情况,值得研究研究的。 */ sum+=distance(j,h,tmp,linjiebiao)-distance(j, index[0], index[1],linjiebiao); } return sum;}int smallest_distance_index(int index[2],int h,double linjiebiao[5][5]) //判断点h属于那个中心点以便形成簇{ int i,result=index[0]; for(i=0;i<2;i++) if(linjiebiao[index[i]][h]<linjiebiao[index[0]][h]) result=index[i]; return result;}void reposition(mem memlist[5], double linjiebiao[5][5]) //PAM算法关键函数,是该算法的核心体现{ int count,count1,h,i,k,holdi,holdh,index[2]; double tempdif;/*hiro:记录最小总代价*/ bool tmp; do {//------------------------每次训话计算出更新后的两个中心点的序号 count1=0; for(k=0;k<5;k++) { if(memlist[k].isMedoid==true) { index[count1]=k; count1++; } }//------------------------- count=0; for(h=0;h<5;h++) { for(i=0;i<5;i++) {/*hiro:遍历所有Oh非代表&&Oi为代表的组合*/ if(memlist[h].isMedoid==false&&memlist[i].isMedoid==true) { if(count==0) { tempdif=TC(index,i,h,linjiebiao); holdi=i; holdh=h; count++; } else if (TC(index,i,h,linjiebiao)<tempdif) {/*不断比较取记录最小的TC相应的值和下标*/ tempdif=TC(index,i,h,linjiebiao); holdi=i; holdh=h; count++; } } } } if (tempdif<0)/*hiro:P173:当最小总代价为正,可以认为认为算法结束*/ { /*hiro:交换原中心点和新中心点的信息*/ tmp=memlist[holdi].isMedoid; memlist[holdi].isMedoid=memlist[holdh].isMedoid; memlist[holdh].isMedoid=tmp; } else if(tempdif>=0) break; //-----------------------test--------// if(test==1)// cout<<"Yes"<<endl; //-------------------------test---------- } while(1);}void main() //主函数,提供邻接矩阵,出示成员集合等PAM算法需要的输入项{ int i,h,count; int index[2]; //用来存储为中心点的两个点的索引 PLinkQueue pq[2]; //预备两个队列用以存储表示两个簇 pq[0]=createEmptyQueue_link(); //队列0的创建 pq[1]=createEmptyQueue_link(); //队列1的创建 double linjiebiao[5][5]={{0,1,2,2,3},{1,0,2,4,3},{2,2,0,1,5},{2,4,1,0,3},{3,3,5,3,0}}; //初始化邻接矩阵 struct mem memlist[5]={{false,'A'},{false,'B'},{false,'C'},{false,'D'},{false,'E'}}; //初始化成员集合 showCase(linjiebiao);/*hiro:可注释*/ cout<<"期望得到的簇的数目暂定为 2 为例。"<<endl; cout<<endl<<endl<<endl; arbStart(memlist); //随意确定两个点作为中心点 cout<<"初始化后的中心点分布情况:"<<endl; int k; for(k=0;k<5;k++) cout<<memlist[k].symbol<<" "<<memlist[k].isMedoid<<endl; /*hiro:数据初始化完毕,开跑*/ reposition(memlist,linjiebiao); //PAM算法处理 cout<<endl<<endl<<endl; cout<<"经过PAM算法处理后的中心点分布情况:"<<endl; for(k=0;k<5;k++) cout<<memlist[k].symbol<<" "<<memlist[k].isMedoid<<endl; cout<<endl<<endl<<endl; /*hiro:得到两个中心点以后开始处理两个簇*/ count=0; for(i=0;i<5;i++) { if(memlist[i].isMedoid==true) {// cout<<memlist[i].symbol<<"是最终得到的中心点"<<endl; enQueue_Link(pq[count], memlist[i]); index[count]=i; count++; } } for(h=0;h<5;h++) { if(memlist[h].isMedoid==false) { if(smallest_distance_index(index,h,linjiebiao)==index[0]) enQueue_Link(pq[0], memlist[h]); else if(smallest_distance_index(index,h,linjiebiao)==index[1]) enQueue_Link(pq[1], memlist[h]); } } cout<<"以以上两个中心点为中心的两个簇为:"<<endl; showQueue(pq[0]); showQueue(pq[1]);}
感想
额虽然应该可能大概没有在等更的同学,但是最近的确精力放在了其他地方,课程也差不多跟上了我之前的进度了,于是回来把剩下的两个算法给写了。。。嗯,我才不是懒更,只是在鼓捣别的【逃】
这个算法虽然简单,但是时间复杂度好高啊。。。。。
先不说一开始就要准备N^2(无论空间上还是时间上)的距离数据,在一次迭代当中,跑的好像还是N^2啊…,不过还好可以并发解决性能问题。
这份源码怎么说呢。。。其实用STL替代自己实现的队列可以少一堆代码,,然后还有各种各样的小地方看起来都很冗余,可以再精简很多的。。
回到算法本身来讲本质上和之前的K-means思路是很像的,只是一些距离衡量和中心点的选取上决策不一样了。
0 0
- DM&ML_note.6-K-中心点聚类算法
- DM&ML_note.5-K-means聚类算法
- DM&ML_note.7-神经网络聚类算法:SOM
- K中心点聚类算法
- DM&ML_note.4-BP神经网络算法
- K-中心点聚类算法(K-Medoide)
- DM&ML_note.1-Apriori
- 聚类分析--k中心点算法
- 聚类分析--k中心点算法
- K-mediods(K中心点)算法
- DM&ML_note.2.1-ID3决策树
- 文本挖掘之文本聚类算法之PAM(k-中心点)
- K中心点算法(K-medoids)
- DM&ML_note.2.2-C4.5决策树
- DM&ML_note.3-朴素贝叶斯分类器
- K中心点
- DM里的K均值算法
- 聚类分析(三) K中心点算法(k-mediods)
- java 遍历arrayList的四种方法
- Python wheel /whl 文件包的正确安装
- java中i++和++i
- 顺序表
- 为了保护眼睛,将eclipse背景色调成豆沙绿
- DM&ML_note.6-K-中心点聚类算法
- centos6.5 salt的操作日志写入数据库
- CentOS7配置samba与Windows共享文件
- Nachos操作系统:Pro1.3:完成Alarm类
- AP聚类算法
- 微信小程序9---Button按钮和icon图标
- 周一
- 苏嵌8 16.11.7
- Leetcode329: Longest Increasing Path in a Matrix