模糊聚类


模糊聚类与K-means算法有异曲同工之妙,两者各有优劣势,K-means算法的介绍连接:https://www.cnblogs.com/bokeyuancj/p/11460883.html

基本概念:

聚类分析是多元统计分析的一种,也是无监督模式识别的一个重要分支,在模式分类 图像处理和模糊规则处理等众多领域中获得最广泛的应用。它把一个没有类别标记的样本按照某种准则划分为若干子集,使相似的样本尽可能归于一类,而把不相似的样本划分到不同的类中。硬聚类把每个待识别的对象严格的划分某类中,具有非此即彼的性质,而模糊聚类建立了样本对类别的不确定描述,更能客观的反应客观世界,从而成为聚类分析的主流。模糊聚类算法是一种基于函数最优方法的聚类算法,使用微积分计算技术求最优代价函数,在基于概率算法的聚类方法中将使用概率密度函数,为此要假定合适的模型,模糊聚类算法的向量可以同时属于多个聚类,从而摆脱上述问题。

模糊聚类分析算法大致可分为三类

(1)分类数不定,根据不同要求对事物进行动态聚类,此类方法是基于模糊等价矩阵聚类的,称为模糊等价矩阵动态聚类分析法。

(2)分类数给定,寻找出对事物的最佳分析方案,此类方法是基于目标函数聚类的,称为模糊C均值聚类。

(3)在摄动有意义的情况下,根据模糊相似矩阵聚类,此类方法称为基于摄动的模糊聚类分析法

本次仅介绍模糊C均值聚类。

隶属度概念:

模糊聚类算法是一种基于划分的聚类算法,它的思想就是使得被划分到同一簇的对象之间相似度最大,而不同簇之间的相似度最小。模糊聚类(FCM)对数据进行模糊划分,使用隶属度表示一个样本属于某一类的程度。

隶属度函数是表示一个对象x 隶属于集合A 的程度的函数,通常记做μA(x),其自变量范围是所有可能属于集合A 的对象(即集合A 所在空间中的所有点),取值范围是[0,1],即0<=μA(x),μA(x)<=1。μA(x)=1 表示x 完全隶属于集合A,相当于传统集合概念上的x∈A。一个定义在空间X={x}上的隶属度函数就定义了一个模糊集合A,或者叫定义在论域X={x}上的模糊子集A’。对于有限个对象x1,x2,……,xn 模糊集合A’可以表示为:

在聚类的问题中,可以把聚类生成的簇看成模糊集合,因此,每个样本点隶属于簇的隶属度就是[0,1]区间里面的值。

模糊聚类算法步骤:

(1)确定类别数,参数,和迭代停止误差以及最大迭代次数

(2)初始化聚类中心P

(3)计算初始的距离矩阵D

(4)按下列公式更新隶属度

(5)按公式更新隶属度

(6)更新聚类中心

(7)重新计算距离矩阵,并计算目标函数的值

(8)若达到最大迭代次数或者前后两次的J的绝对差小于迭代停止误差则停止,否则使用前后两次隶属度矩阵的差来判断。

(9)将样本点划分为隶属度最大的那一类。

 数据样本:

数据量1500(条)
数据属性(影响变量)5(种)
属性1花片长度(厘米)
属性2花片宽度(厘米)
属性3花瓣长度(厘米)
属性4花瓣宽度(厘米)
属性5花叶数量(片)

 代码部分:

  1 #include "stdio.h"
  2 #include "stdlib.h"
  3 #include "time.h"
  4 #include "math.h"
  5 #include "vector"
  6 using namespace std;
  7
  8
  9 #define alpha 0.5   //分裂比
 10 #define dimNum 3   //维数为3
 11 #define cNum 10  //初始类数
 12 #define expectNum 10  //预期成类数
 13 #define minNum 3     //小于此数则不能成类
 14 #define splitVar 1.2  //大于此数分裂
 15 #define connectVar 0.3  //小于此数合并
 16 #define connectNum 2   //每次迭代允许合并的最大数
 17 #define iterNum 30  //迭代次数为30
 18
 19
 20
 21
 22 typedef vector<double> doubleVector;
 23 typedef vector<doubleVector> clusterVector;
 24
 25
 26 void ISODATA(vector<doubleVector> srcInf);  //开始引擎
 27 vector<doubleVector> getInf();  //获取文件数据
 28 int getClusterNum(vector<doubleVector> mCenter, doubleVector srcInf); //归类
 29 double getEUCdis(doubleVector t1, doubleVector t2);  //计算欧式距离
 30 doubleVector get_wMean(clusterVector cluster);  //计算均值向量
 31 doubleVector averageDist(doubleVector mCenter, clusterVector cluster); //计算Wi中所有样本距其相应聚类中心的平均距离
 32 doubleVector allAvgDist(vector<doubleVector> avgDis); //计算所以样本距其相应的聚类中心的平均值
 33 doubleVector getDeviation(doubleVector mCenter, clusterVector cluster); //计算没一聚类的标准偏差
 34 double getMaxDev(doubleVector Dev);  //获取最大标准偏差
 35 doubleVector clusterSplit(doubleVector wMean, double sigma);  //进行分裂
 36 doubleVector eachCenterDist(doubleVector t1, doubleVector t2, int i, int j);  //计算聚类中心两两间的距离
 37 vector<doubleVector> distSort(vector<doubleVector> eachDist);   //按距离进行排序
 38 vector<doubleVector> Union(vector<doubleVector> mCenter, vector<doubleVector> sortDist); //进行合并
 39 void Output(vector<clusterVector> cluster);  //结果输出
 40
 41
 42 //主函数
 43 int main()
 44 {
 45 vector<doubleVector> srcInf;
 46 srcInf = getInf();
 47 ISODATA(srcInf);
 48 }
 49
 50
 51
 52
 53 //迭代开始引擎
 54 void ISODATA(vector<doubleVector> srcInf)
 55 {
 56 int c;
 57 int i, j;
 58 int iter=1;
 59 int lable;
 60 vector<doubleVector> mCenter;
 61 vector<clusterVector> cluster;
 62 vector<doubleVector> wMean;   //均值向量
 63 vector<doubleVector> avgDist;
 64 doubleVector all_AvgDis;
 65 vector<doubleVector> devVal;  //标准偏差值
 66 vector<doubleVector> eachDist;  //两两聚类中心距离
 67 vector<doubleVector> eachDistSort;  //两两聚类中心距离
 68 doubleVector devMax;   //最大偏差值
 69 double sigma;
 70
 71
 72 start:
 73 printf("聚类开始:\n");
 74
 75
 76
 77
 78 //初始化类聚中心
 79 step1:
 80 srand(time(NULL));
 81 int chooseNum;
 82 if(mCenter.empty()==NULL)
 83 mCenter.clear();
 84
 85
 86 mCenter.resize(cNum);
 87 for(i=0; i<cNum; i++)
 88 {
 89 chooseNum = rand()%(int)(srcInf.size()/cNum)+i*(srcInf.size()/cNum);
 90 for(j=0; j<dimNum; j++)
 91 mCenter[i].push_back(srcInf[chooseNum][j]);
 92 }
 93
 94
 95
 96
 97 //根据距离归类
 98 step2:
 99 if(cluster.empty()==NULL)
100 cluster.clear();
101
102
103 cluster.resize(2*cNum);
104 for(i=0; i<srcInf.size(); i++)
105 {
106 lable = getClusterNum(mCenter, srcInf[i]);
107 cluster[lable].push_back(srcInf[i]);
108 }
109
110
111
112
113 //舍弃过小的类
114 step3:
115 for(i=0; i<cluster.size(); )
116 {
117 if(cluster[i].size()<minNum)
118 {
119 cluster.erase(cluster.begin()+i);
120 if(i<mCenter.size())
121 mCenter.erase(mCenter.begin()+i);
122 }
123
124 else
125 i++;
126 }
127 c = mCenter.size();
128
129
130
131
132 //更新均值向量
133 step4:
134 if(wMean.empty()==NULL)
135 wMean.clear();
136
137
138 for(i=0; i<cluster.size(); i++)
139 wMean.push_back(get_wMean(cluster[i]));
140
141
142
143 //获取各平均距离
144 step5:
145 if(avgDist.empty()==NULL)
146 avgDist.clear();
147
148
149 for(i=0; i<cluster.size(); i++)   //计算Wi中所有样本距其相应聚类中心的平均距离
150 avgDist.push_back(averageDist(mCenter[i], cluster[i]));
151
152
153 all_AvgDis = allAvgDist(avgDist);  //计算所以样本距其相应的聚类中心的平均值
154
155
156
157
158 //判断分裂、合并及迭代的运算步骤
159 step7:
160 if(iter==iterNum)   //步骤(1)
161 {
162
163 // connectNum = 0;
164 goto step11;
165 }
166
167
168 if(c<=expectNum/2)//步骤(2)
169 goto step8;
170
171
172 if(iter%2==0 || c>=2*expectNum)//步骤(3)
173 goto step11;
174
175
176
177
178 //计算标准偏差
179 step8:
180 if(devVal.empty()==NULL)
181 devVal.clear();
182
183
184 for(i=0; i<mCenter.size(); i++)   //计算标准偏差
185 devVal.push_back(getDeviation(mCenter[i], cluster[i]));
186
187
188
189
190
191
192 //计算标准偏差中偏差最大值
193 step9:
194 if(devMax.empty()==NULL)
195 devMax.clear();
196
197
198 for(i=0; i<devVal.size(); i++)    //计算标准偏差中偏差最大值
199 devMax.push_back(getMaxDev(devVal[i]));
200
201
202
203
204
205
206 //进行分裂
207 step10:
208 for(i=0; i<devMax.size(); i++)
209 {
210 if((devMax[i]>splitVar && cluster[i].size()>2*minNum) || c<=expectNum/2)
211 {
212 sigma = alpha*devMax[i];
213 mCenter.push_back(clusterSplit(wMean[i], sigma));
214 mCenter.push_back(clusterSplit(wMean[i], -sigma));
215 mCenter.erase(mCenter.begin()+i);
216 }
217 }
218 c = mCenter.size();
219
220
221
222
223 //计算两两聚类间的距离
224 step11:
225 if(eachDist.empty()==NULL)
226 eachDist.clear();
227
228
229 for(i=0; i<mCenter.size()-1; i++)
230 for(j=i+1; j<mCenter.size(); j++)
231 {
232 eachDist.push_back(eachCenterDist(mCenter[i], mCenter[j], i, j));
233
234 }
235
236
237
238
239
240
241 //对距离进行排序
242 step12:
243 eachDistSort = distSort(eachDist);
244
245
246
247
248 //进行合并
249 step13:
250 mCenter = Union(mCenter, eachDistSort);
251 c = mCenter.size();
252
253
254
255
256 step14:
257 if(iter==iterNum)
258 {
259 printf("类聚结果为:\n");
260 Output(cluster);
261 system("pause");
262 return;
263 }
264
265
266 else
267 {
268 iter++;
269 goto step2;
270 }
271
272
273 }
274
275
276
277
278
279
280 //获取文件数据
281 vector<doubleVector> getInf()
282 {
283 int i=1;
284 vector<doubleVector> dst;
285 doubleVector temp;
286 double num;
287
288 FILE *fp;
289
290 fp = fopen("Inf.txt","r");
291 //fp = fopen("Inf.txt", "r");
292
293 if(fp == NULL)
294 printf("Open file error!\n");
295
296 //读取文件的数据
297 while(fscanf(fp, "%lf", &num)!=EOF)
298 {
299 temp.push_back(num);
300 if(i%3==0)
301 {
302 dst.push_back(temp);
303 temp.clear();
304 }
305 i++;
306 }
307
308 fclose(fp);
309
310 return dst;
311 }
312
313
314
315
316 //计算欧式距离
317 double getEUCdis(doubleVector t1, doubleVector t2)
318 {
319 double distance=0;
320 int i;
321
322
323 for(i=0; i<dimNum; i++)
324 distance += (t1[i]-t2[i])*(t1[i]-t2[i]);
325
326
327 return sqrtf(distance);
328 }
329
330
331 //根据初始中心进行归类
332 int getClusterNum(vector<doubleVector> mCenter, doubleVector srcInf)
333 {
334 double Dis;
335 double minDis = getEUCdis(mCenter[0], srcInf);
336 int i, lable=0;
337
338
339 for(i=1; i<mCenter.size(); i++)
340 {
341 Dis = getEUCdis(mCenter[i], srcInf);
342 if(Dis<minDis)
343 {
344 minDis = Dis;
345 lable = i;
346 }
347 }
348
349
350 return lable;
351 }
352
353
354
355
356 //计算均值向量
357 doubleVector get_wMean(clusterVector cluster)
358 {
359 doubleVector wMean;
360 double temp[dimNum];
361 int i, j;
362
363
364 for(i=0; i<dimNum; i++)
365 temp[i] = 0;
366
367
368 for(i=0; i<cluster.size(); i++)
369 for(j=0; j<dimNum; j++)
370 temp[j] += cluster[i][j];
371
372
373 for(i=0; i<dimNum; i++)
374 temp[i] = temp[i]/cluster.size();
375
376
377 wMean.clear();
378 for(i=0; i<dimNum; i++)
379 wMean.push_back(temp[i]);
380
381
382 return wMean;
383 }
384
385
386
387
388 //计算类聚中心m[i]的平均距离
389 doubleVector averageDist(doubleVector mCenter, clusterVector cluster)
390 {
391   int i, j;
392   doubleVector avgDist;
393 double temp[dimNum]={0};
394
395
396 for(i=0; i<cluster.size(); i++)
397 for(j=0; j<dimNum; j++)
398 temp[j] += cluster[i][j];
399
400
401 for(i=0; i<dimNum; i++)
402 temp[i] /= cluster.size();
403
404
405 avgDist.clear();
406 for(i=0; i<dimNum; i++)
407 avgDist.push_back(temp[i]);
408
409
410 return avgDist;
411
412
413 }
414
415
416
417
418 //计算所以样本距其相应的聚类中心的平均值
419 doubleVector allAvgDist(vector<doubleVector> avgDis)
420 {
421 int i, j;
422 doubleVector allAvg;
423 double temp[dimNum]={0};
424
425
426 for(i=0; i<avgDis.size(); i++)
427 for(j=0; j<dimNum; j++)
428 temp[j] += (i+1)*avgDis[i][j];
429
430
431 for(i=0; i<dimNum; i++)
432 temp[i] /= avgDis.size();
433
434
435 allAvg.clear();
436 for(i=0; i<dimNum; i++)
437 allAvg.push_back(temp[i]);
438
439
440 return allAvg;
441 }
442
443
444
445
446 //计算每一个聚类的标准偏差
447 doubleVector getDeviation(doubleVector mCenter, clusterVector cluster)
448 {
449 doubleVector dst;
450 int i, j;
451 double temp[dimNum]={0};
452
453
454 for(i=0; i<cluster.size(); i++)
455 for(j=0; j<dimNum; j++)
456 temp[j] += (cluster[i][j]-mCenter[j])*(cluster[i][j]-mCenter[j]);
457
458
459 dst.clear();
460 for(i=0; i<dimNum; i++)
461 {
462 temp[i] /= cluster.size();
463 temp[i] = sqrtf(temp[i]);
464 dst.push_back(temp[i]);
465 }
466
467
468 return dst;
469
470
471 }
472
473
474
475
476 //获取最大标准偏差
477 double getMaxDev(doubleVector Dev)
478 {
479 int i;
480 double max = Dev[0];
481
482
483 for(i=1; i<dimNum; i++)
484 if(max<Dev[i])
485 max = Dev[i];
486
487
488 return max;
489 }
490
491
492
493
494 //进行分裂
495 doubleVector clusterSplit(doubleVector wMean, double sigma)
496 {
497 int i;
498 doubleVector newMean;
499 double temp;
500
501
502 newMean.clear();
503 for(i=0; i<dimNum; i++)
504 {
505 temp = wMean[i]+sigma;
506 newMean.push_back(temp);
507 }
508
509
510 return newMean;
511 }
512
513
514
515
516 //计算聚类中心两两间的距离
517 doubleVector eachCenterDist(doubleVector t1, doubleVector t2, int x, int y)
518 {
519 int i;
520 doubleVector dist;
521
522
523 dist.clear();
524 for(i=0; i<dimNum; i++)
525 dist.push_back(fabs(t1[i]-t2[i]));
526
527
528 dist.push_back(x);
529 dist.push_back(y);
530
531
532 return dist;
533 }
534
535
536
537
538 //按距离进行排序
539 vector<doubleVector> distSort(vector<doubleVector> eachDist)
540 {
541 int i, j, l;
542 vector<doubleVector> dst;
543 doubleVector maxEachDist;
544 double temp;
545 doubleVector tempVet;
546 double min;
547
548
549 dst = eachDist;
550 //寻找每组中最大的距离
551 maxEachDist.clear();
552 for(i=0; i<eachDist.size(); i++)
553 maxEachDist.push_back(getMaxDev(eachDist[i]));
554
555
556 //排序
557 for(i=0; i<maxEachDist.size(); i++)
558 {
559 l=i;
560 min = maxEachDist[i];
561 for(j=i+1; j<maxEachDist.size(); j++)
562 if(min>maxEachDist[j])
563 {
564 min = maxEachDist[j];
565 l = j;
566 }
567
568
569 temp = maxEachDist[i];
570 maxEachDist[i] = maxEachDist[l];
571 maxEachDist[l] = temp;
572
573
574 tempVet = dst[i];
575 dst[i] = dst[l];
576 dst[l] = tempVet;
577 }
578
579
580 return dst;
581 }
582
583
584
585
586 //进行合并
587 vector<doubleVector> Union(vector<doubleVector> mCenter, vector<doubleVector> sortDist)
588 {
589 int i[connectNum], j[connectNum];
590 int m, n, delNum=0;
591 vector<doubleVector> newCenter;
592 vector<int> del;
593 doubleVector temp;
594
595
596 newCenter = mCenter;
597
598
599 //可联合数量
600 for(m=0; m<connectNum; m++)
601 for(n=0; n<dimNum; n++)
602 if(sortDist[m][n]<connectVar)
603 {
604 delNum++;
605 break;
606 }
607
608
609 //进行联合
610 for(m=0; m<delNum; m++)
611 {
612 i[m] = sortDist[m][dimNum];
613 j[m] = sortDist[m][dimNum+1];
614
615
616 for(n=0; n<dimNum; n++)
617 temp.push_back((i[m]*mCenter[i[m]][n]+j[m]*mCenter[j[m]][n])/(i[m]+j[m]));
618
619
620 newCenter.push_back(temp);
621 }
622
623
624 //避免重复删除
625 for(m=0; m<delNum; m++)
626 del.push_back(i[m]);
627
628 for(n=0; n<delNum; n++)
629 {
630 if(del[n]==j[n])
631 continue;
632 else
633 del.push_back(j[n]);
634 }
635
636
637
638   for(m=0; m<del.size(); m++)
639   newCenter[del[m]].clear();
640
641
642 for(m=0; m<newCenter.size(); )
643 {
644 if(newCenter[m].empty())
645 newCenter.erase(newCenter.begin()+m);
646 else
647 m++;
648 }
649
650 return newCenter;
651 }
652
653
654
655
656 //结果输出
657 void Output(vector<clusterVector> cluster)
658 {
659 int i, j, k;
660
661
662 for(i=0; i<cluster.size(); i++)
663 {
664 printf("\n类聚%d :\n", i+1);
665 for(j=0; j<cluster[i].size(); j++)
666 printf("%lf  %lf  %lf  %lf  %lf\n", cluster[i][j][0], cluster[i][j][1], cluster[i][j][2], cluster[i][j][4], cluster[i][j][5]);
667 }
668 }

运行结果:

第一次运行

程序运行

- 输出大小: 1.64986419677734 MiB
- 编译时间: 1.06s

第二次运行

程序运行

- 输出大小: 1.64986419677734 MiB
- 编译时间: 1.09s

 运行第三次

 程序运行

- 输出大小: 1.64986419677734 MiB
- 编译时间: 1.08s

K-Means算法与聚类算法优缺点对比

K-Means算法的优点:

1.算法快速、简单;

2.对大数据集有较高的效率并且是可伸缩性的;

3.时间复杂度近于线性,而且适合挖掘大规模数据集。

K-Means聚类算法的时间复杂度是O(nkt) ,其中n代表数据集中对象的数量,t代表着算法迭代的次数,k代表着簇的数目。


模糊聚类算法优点:

 1.FCM方法会计算每个样本对所有类的隶属度,拥有样本分类结果可靠性的计算方法;

 2.样本分类更加保险

但是模糊聚类算法的不足之处是计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。其时间复杂度为O(n3log2n),且存储开销大,很难处理大规模的数据

 


参考博客:

https://blog.csdn.net/wzl1997/article/details/79264560

https://blog.csdn.net/u012871279/article/details/51656027

 http://archive.ics.uci.edu/ml/index.php

https://blog.csdn.net/u013049912/article/details/84782857

02-01 00:45