模糊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 }

 

posted on 2020-04-30 13:27  hyacinthhome  阅读(405)  评论(0编辑  收藏  举报