模糊c-means算法的c++实现
首先输入点的个数,维度,分类数目
我的代码FCM中主要过程如下:
1:(init_c函数)随机初始化聚类中心
2:(comp_dis函数)计算每个点到每个聚类距离 dis[i][j] 表示i点到j聚类中心的距离
3:(while(1))进入循环
4:(comp_u函数)计算隶属度矩阵u[i][j]表示i点对应j聚类中心的隶属度
5:(update_c函数)根据隶属度和每个点的位置更新聚类中心
6:(compdis函数)因为聚类中心更新了嘛,再重新计算下每个点到每个聚类中心的距离
7:(comp_obj_func函数)计算函数值差值如果小于设定值eps则进行第8步,否则进行第9步
8:(break)退出循环
9:根据每个点的隶属度情况,给每个点分类(距离哪个聚类中心近,就给谁)
注意事项:
1.如果点很少的话,可能在我的初始化聚类中心函数中会有相同的点,造成分类错误,但实际应用中,点数足够多的情况则这个概率可以忽略
2.在计算隶属度的函数中,如果一个点距离一个聚类中心足够的近,那么直接将它的隶属度设置成1,其他的为0
其他:
如果有错误和疑问欢迎探讨,望多多指教!
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<vector> 4 #include<fstream> 5 #include<cmath> 6 #include<ctime> 7 #include<cstdlib> 8 using namespace std; 9 struct Mode 10 { 11 int x,y; 12 int di; 13 vector<double> datas; 14 }; 15 typedef vector<vector<Mode> > ModeVec; 16 const int N=1000; 17 const double eps=1e-2; 18 const double eps_dis=1e-6; 19 20 double getDistance(Mode &m1,Mode &m2); 21 void FCM(Mode *p,int n,int di,int clusternum,vector<vector<Mode> > &ans); 22 void init_c(Mode *p,int n,int clusternum,Mode *c); 23 void comp_dis(Mode *p,Mode *c,int n,int clusternum,double dis[][10]); 24 void comp_u(double dis[][10],int n,int clusternum,double u[][10]); 25 void update_c(Mode *p,double u[][10],int n,int clusternum,Mode *c); 26 double comp_obj_func(double u[][10],double dis[][10],int n,int clusternum,int di); 27 int main() 28 { 29 int n,dimension,clusternum; 30 Mode p[N]; 31 // freopen("in.txt","r",stdin); 32 // freopen("out.txt","w",stdout); 33 ifstream fin("in.txt"); 34 ofstream fout("out.txt"); 35 fin>>n>>dimension>>clusternum; //输入点的个数,维度,聚类数目 36 for(int i=0; i<n; i++) 37 { 38 p[i].di=dimension; 39 for(int j=0; j<dimension; j++) 40 { 41 double temp; 42 fin>>temp; 43 p[i].datas.push_back(temp); 44 } 45 } 46 vector<vector<Mode> > ans; 47 FCM(p,n,dimension,clusternum,ans); //传入数组p,有n个点,维度为dimension,结果保存在ans 48 for(int i=0;i<clusternum;i++) 49 { 50 printf("第%d类:\n",i+1); 51 for(int j=0;j<ans[i].size();j++) 52 { 53 printf("("); 54 for(int k=0;k<dimension;k++) 55 { 56 if(k==0) printf("%f",ans[i][j].datas[k]); 57 else printf(",%f",ans[i][j].datas[k]); 58 } 59 printf(") "); 60 } 61 printf("\n"); 62 } 63 return 0; 64 } 65 double getDistance(Mode &m1,Mode &m2) 66 { 67 int di=m1.di; 68 double ans=0; 69 for(int i=0; i<di; i++) 70 ans+=(m1.datas[i]-m2.datas[i])*(m1.datas[i]-m2.datas[i]); 71 return ans; 72 } 73 void init_c(Mode *p,int n,int clusternum,Mode *c) //初始化聚类中心 74 { 75 int di=p[0].di; 76 srand(time(NULL)); 77 for(int i=0;i<clusternum;i++) 78 { 79 c[i].di=di; 80 c[i].datas.clear(); 81 for(int j=0;j<di;j++) 82 c[i].datas.push_back(0); 83 } 84 for(int i=0;i<n;i++) 85 for(int j=0;j<di;j++) 86 for(int k=0;k<clusternum;k++) 87 c[k].datas[j]+=p[i].datas[j]; 88 for(int i=0;i<clusternum;i++) 89 { 90 for(int j=0;j<di;j++) 91 { 92 int tp=rand()%n+1; 93 c[i].datas[j]/=tp; 94 } 95 } 96 } 97 void comp_dis(Mode *p,Mode *c,int n,int clusternum,double dis[][10]) //初始化每个点和每个簇的距离 98 { 99 for(int i=0; i<n; i++) 100 for(int j=0; j<clusternum; j++) 101 dis[i][j]=getDistance(p[i],c[j]); 102 } 103 void comp_u(double dis[][10],int n,int clusternum,double u[][10]) //计算隶属度矩阵 104 { 105 for(int i=0; i<n; i++) 106 { 107 double tp=0; 108 for(int j=0;j<clusternum;j++) 109 { 110 if(dis[i][j]<eps_dis) //如果这个点很接近一个簇类中心,那么这个隶属度设为1,其他为0 111 { 112 for(int k=0;k<clusternum;k++) 113 u[i][k]=0; 114 u[i][j]=1; 115 return; 116 } 117 tp+=1/dis[i][j]; 118 } 119 tp=1/tp; 120 for(int j=0; j<clusternum; j++) 121 u[i][j]=tp*(1/dis[i][j]); 122 } 123 } 124 void update_c(Mode *p,double u[][10],int n,int clusternum,Mode *c) 125 { 126 int di=p[0].di; 127 for(int j=0;j<clusternum;j++) 128 { 129 c[j].di=di; 130 c[j].datas.clear(); 131 for(int i=0;i<di;i++) 132 c[j].datas.push_back(0); 133 double tp=0; 134 for(int i=0;i<n;i++) 135 { 136 for(int k=0;k<di;k++) 137 c[j].datas[k]+=u[i][j]*u[i][j]*p[i].datas[k]; 138 tp+=u[i][j]*u[i][j]; 139 } 140 for(int k=0;k<di;k++) 141 c[j].datas[k]/=tp; 142 } 143 } 144 double comp_obj_func(double u[][10],double dis[][10],int n,int clusternum,int di) 145 { 146 double sum=0; 147 for(int i=0;i<n;i++) 148 for(int j=0;j<clusternum;j++) 149 sum+=u[i][j]*u[i][j]*dis[i][j]; 150 return sum; 151 } 152 void FCM(Mode *p,int n,int di,int clusternum,vector<vector<Mode> > &ans) //in: n,d,c time:O(c*n*d) 时间复杂度=聚类数*点数*维数 153 { 154 int index=0; 155 double sum=0,psum; 156 Mode c[10]; //聚类中心 157 double dis[N][10]; //距离 158 double u[N][10]; //隶属度矩阵 159 init_c(p,n,clusternum,c); // 初始化聚类中心 time: O(c) 160 comp_dis(p,c,n,clusternum,dis); //更新距离矩阵dis 161 while(1) 162 { 163 index++; 164 printf("第%d次循环----------------------------------------\n",index); 165 comp_u(dis,n,clusternum,u); //计算隶属度矩阵u time:O(n*c); 166 for(int i=0;i<n;i++) 167 { 168 printf("第%d个点的隶属值\n",i+1); 169 for(int j=0;j<clusternum;j++) 170 { 171 printf("%f ",u[i][j]); 172 } 173 printf("\n"); 174 } 175 update_c(p,u,n,clusternum,c); //更新聚类中心 time:O(c*(2*d+(n*d))) = O(c*n*d) 176 comp_dis(p,c,n,clusternum,dis); //重新计算距离矩阵 177 psum=sum; 178 sum=comp_obj_func(u,dis,n,clusternum,di); 179 printf("函数值=%f\n",sum); 180 if(fabs(psum-sum)<eps) 181 break; 182 } 183 for(int i=0;i<clusternum;i++) 184 { 185 vector<Mode> m; 186 ans.push_back(m); 187 } 188 for(int i=0;i<n;i++) 189 { 190 double tp=-1; 191 int index=0; 192 for(int j=0;j<clusternum;j++) 193 { 194 if(u[i][j]>tp) 195 { 196 tp=u[i][j]; 197 index=j; 198 } 199 } 200 ans[index].push_back(p[i]); 201 } 202 }