模糊C均值聚类(FCM)算法(IOSDATA)+ c语言代码

时间:2022-01-24 23:04:26

本代码算法用例为鸢尾花数据集合;

IOSDATA算法实现步骤,在很多资料和论坛中都有详细的介绍,这里就不对算法步骤进行陈述了。

就我代码中,我对下面几个控制参数的理解:

初始聚类数:初始类聚中心,跟聚类聚中心划分簇。

期望得到的聚类数:这个数并不是最终得到的类聚数目,可以理解为我们人为的预估可能得到的类聚数,最后的结果不一定与这个数相等。

最大迭代次数:控制程序的迭代次数,根据样本数量大小设置,本代码中的最大迭代次数设置为10,但迭代到4步左右就已经类聚完成了。

其他的一些控制参数看注解或一些资料便知道其作用,这里就不做多余介绍。


建议先将K-MEAN聚类算法看懂,再看IOSDATA聚类算法,程序理解就容易多。K-MEAN算法的代码和实现步骤在我之前的博客中也有。

c语言代码如下:

(代码并不是很完美,当类聚得到的数目过少(本例为<3时)时会出现错误,本代码仅供学习参考)

#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#include "math.h"
#include "vector"
using namespace std;


#define alpha 0.5   //分裂比
#define dimNum 3   //维数为3
#define cNum 8  //初始类数
#define expectNum 4  //预期成类数
#define minNum 3     //小于此数则不能成类
#define splitVar 1.2  //大于此数分裂
#define connectVar 0.3  //小于此数合并
#define connectNum 2   //每次迭代允许合并的最大数
#define iterNum 10  //迭代次数为10




typedef vector<double> doubleVector;
typedef vector<doubleVector> clusterVector;


void ISODATA(vector<doubleVector> srcInf);  //开始引擎
vector<doubleVector> getInf();  //获取文件数据
int getClusterNum(vector<doubleVector> mCenter, doubleVector srcInf); //归类
double getEUCdis(doubleVector t1, doubleVector t2);  //计算欧式距离
doubleVector get_wMean(clusterVector cluster);  //计算均值向量
doubleVector averageDist(doubleVector mCenter, clusterVector cluster); //计算Wi中所有样本距其相应聚类中心的平均距离
doubleVector allAvgDist(vector<doubleVector> avgDis); //计算所以样本距其相应的聚类中心的平均值
doubleVector getDeviation(doubleVector mCenter, clusterVector cluster); //计算没一聚类的标准偏差
double getMaxDev(doubleVector Dev);  //获取最大标准偏差
doubleVector clusterSplit(doubleVector wMean, double sigma);  //进行分裂
doubleVector eachCenterDist(doubleVector t1, doubleVector t2, int i, int j);  //计算聚类中心两两间的距离
vector<doubleVector> distSort(vector<doubleVector> eachDist);   //按距离进行排序
vector<doubleVector> Union(vector<doubleVector> mCenter, vector<doubleVector> sortDist); //进行合并
void Output(vector<clusterVector> cluster);  //结果输出


//主函数
void main()
{
vector<doubleVector> srcInf;
srcInf = getInf();
ISODATA(srcInf);
}




//迭代开始引擎
void ISODATA(vector<doubleVector> srcInf)
{
int c;
int i, j;
int iter=1;
int lable;
vector<doubleVector> mCenter;
vector<clusterVector> cluster;
vector<doubleVector> wMean;   //均值向量
vector<doubleVector> avgDist;
doubleVector all_AvgDis;
vector<doubleVector> devVal;  //标准偏差值
vector<doubleVector> eachDist;  //两两聚类中心距离
vector<doubleVector> eachDistSort;  //两两聚类中心距离
doubleVector devMax;   //最大偏差值
double sigma;


start:
printf("聚类开始:\n");




//初始化类聚中心
step1:   
srand(time(NULL));
int chooseNum;
if(mCenter.empty()==NULL)
mCenter.clear();


mCenter.resize(cNum);
for(i=0; i<cNum; i++)
{
chooseNum = rand()%(int)(srcInf.size()/cNum)+i*(srcInf.size()/cNum);
for(j=0; j<dimNum; j++)
mCenter[i].push_back(srcInf[chooseNum][j]);
}




//根据距离归类
step2:  
if(cluster.empty()==NULL)
cluster.clear();


cluster.resize(2*cNum);
for(i=0; i<srcInf.size(); i++)
{
lable = getClusterNum(mCenter, srcInf[i]);
cluster[lable].push_back(srcInf[i]);
}




//舍弃过小的类
step3:
for(i=0; i<cluster.size(); )
{
if(cluster[i].size()<minNum)
{
cluster.erase(cluster.begin()+i);
if(i<mCenter.size())
mCenter.erase(mCenter.begin()+i);
}

else
i++;
}
c = mCenter.size();




//更新均值向量
step4:  
if(wMean.empty()==NULL)
wMean.clear();


for(i=0; i<cluster.size(); i++)
wMean.push_back(get_wMean(cluster[i]));



//获取各平均距离
step5:
if(avgDist.empty()==NULL)
avgDist.clear();


for(i=0; i<cluster.size(); i++)   //计算Wi中所有样本距其相应聚类中心的平均距离
avgDist.push_back(averageDist(mCenter[i], cluster[i]));  


all_AvgDis = allAvgDist(avgDist);  //计算所以样本距其相应的聚类中心的平均值




//判断分裂、合并及迭代的运算步骤
step7:
if(iter==iterNum)   //步骤(1)
{

// connectNum = 0;
goto step11;
}


if(c<=expectNum/2)//步骤(2)
goto step8;


if(iter%2==0 || c>=2*expectNum)//步骤(3)
goto step11;




//计算标准偏差
step8:
if(devVal.empty()==NULL)
devVal.clear();


for(i=0; i<mCenter.size(); i++)   //计算标准偏差
devVal.push_back(getDeviation(mCenter[i], cluster[i]));






//计算标准偏差中偏差最大值
step9:
if(devMax.empty()==NULL)
devMax.clear();


for(i=0; i<devVal.size(); i++)    //计算标准偏差中偏差最大值
devMax.push_back(getMaxDev(devVal[i]));






//进行分裂
step10:
for(i=0; i<devMax.size(); i++)
{
if((devMax[i]>splitVar && cluster[i].size()>2*minNum) || c<=expectNum/2)
{
sigma = alpha*devMax[i];
mCenter.push_back(clusterSplit(wMean[i], sigma));
mCenter.push_back(clusterSplit(wMean[i], -sigma));
mCenter.erase(mCenter.begin()+i);
}
}
c = mCenter.size();




//计算两两聚类间的距离
step11:
if(eachDist.empty()==NULL)
eachDist.clear();


for(i=0; i<mCenter.size()-1; i++)
for(j=i+1; j<mCenter.size(); j++)
{
eachDist.push_back(eachCenterDist(mCenter[i], mCenter[j], i, j));

}






//对距离进行排序
step12:
eachDistSort = distSort(eachDist);




//进行合并
step13:
mCenter = Union(mCenter, eachDistSort);
c = mCenter.size();




step14:
if(iter==iterNum)
{
printf("类聚结果为:\n");
Output(cluster);
system("pause");
return;
}


else
{
iter++;
goto step2;
}


}






//获取文件数据
vector<doubleVector> getInf()
{
int i=1;
vector<doubleVector> dst;
doubleVector temp;
double num;

FILE *fp;

fp = fopen("Inf.txt", "r");

if(fp == NULL)
printf("Open file error!\n");

//读取文件的数据
while(fscanf(fp, "%lf", &num)!=EOF)
{
temp.push_back(num);
if(i%3==0)
{
dst.push_back(temp);
temp.clear();
}
i++;
}

fclose(fp);

return dst;
}




//计算欧式距离
double getEUCdis(doubleVector t1, doubleVector t2)
{
double distance=0;
int i;


for(i=0; i<dimNum; i++)
distance += (t1[i]-t2[i])*(t1[i]-t2[i]);


return sqrtf(distance);
}


//根据初始中心进行归类
int getClusterNum(vector<doubleVector> mCenter, doubleVector srcInf)
{
double Dis;
double minDis = getEUCdis(mCenter[0], srcInf);
int i, lable=0;


for(i=1; i<mCenter.size(); i++)
{
Dis = getEUCdis(mCenter[i], srcInf);
if(Dis<minDis)
{
minDis = Dis;
lable = i;
}
}


return lable;
}




//计算均值向量
doubleVector get_wMean(clusterVector cluster)
{
doubleVector wMean;
double temp[dimNum];
int i, j;


for(i=0; i<dimNum; i++)
temp[i] = 0;


for(i=0; i<cluster.size(); i++)
for(j=0; j<dimNum; j++)
temp[j] += cluster[i][j];


for(i=0; i<dimNum; i++)
temp[i] = temp[i]/cluster.size();


wMean.clear();
for(i=0; i<dimNum; i++)
wMean.push_back(temp[i]);


return wMean;
}




//计算类聚中心m[i]的平均距离
doubleVector averageDist(doubleVector mCenter, clusterVector cluster)
{
  int i, j;
  doubleVector avgDist;
double temp[dimNum]={0};


for(i=0; i<cluster.size(); i++)
for(j=0; j<dimNum; j++)
temp[j] += cluster[i][j];


for(i=0; i<dimNum; i++)
temp[i] /= cluster.size();


avgDist.clear();
for(i=0; i<dimNum; i++)
avgDist.push_back(temp[i]);


return avgDist;


}




//计算所以样本距其相应的聚类中心的平均值
doubleVector allAvgDist(vector<doubleVector> avgDis)
{
int i, j;
doubleVector allAvg;
double temp[dimNum]={0};


for(i=0; i<avgDis.size(); i++)
for(j=0; j<dimNum; j++)
temp[j] += (i+1)*avgDis[i][j];


for(i=0; i<dimNum; i++)
temp[i] /= avgDis.size();


allAvg.clear();
for(i=0; i<dimNum; i++)
allAvg.push_back(temp[i]);


return allAvg;
}




//计算每一个聚类的标准偏差
doubleVector getDeviation(doubleVector mCenter, clusterVector cluster)
{
doubleVector dst;
int i, j;
double temp[dimNum]={0};


for(i=0; i<cluster.size(); i++)
for(j=0; j<dimNum; j++)
temp[j] += (cluster[i][j]-mCenter[j])*(cluster[i][j]-mCenter[j]);


dst.clear();
for(i=0; i<dimNum; i++)
{
temp[i] /= cluster.size();
temp[i] = sqrtf(temp[i]);
dst.push_back(temp[i]);
}


return dst;


}




//获取最大标准偏差
double getMaxDev(doubleVector Dev)
{
int i;
double max = Dev[0];


for(i=1; i<dimNum; i++)
if(max<Dev[i])
max = Dev[i];


return max;
}




//进行分裂
doubleVector clusterSplit(doubleVector wMean, double sigma)
{
int i;
doubleVector newMean;
double temp;


newMean.clear();
for(i=0; i<dimNum; i++)
{
temp = wMean[i]+sigma;
newMean.push_back(temp);
}


return newMean;
}




//计算聚类中心两两间的距离
doubleVector eachCenterDist(doubleVector t1, doubleVector t2, int x, int y)
{
int i;
doubleVector dist;


dist.clear();
for(i=0; i<dimNum; i++)
dist.push_back(fabs(t1[i]-t2[i]));


dist.push_back(x);
dist.push_back(y);


return dist;
}




//按距离进行排序
vector<doubleVector> distSort(vector<doubleVector> eachDist)
{
int i, j, l;
vector<doubleVector> dst;
doubleVector maxEachDist;
double temp;
doubleVector tempVet;
double min;


dst = eachDist;
//寻找每组中最大的距离
maxEachDist.clear();
for(i=0; i<eachDist.size(); i++)
maxEachDist.push_back(getMaxDev(eachDist[i]));


//排序
for(i=0; i<maxEachDist.size(); i++)
{
l=i;
min = maxEachDist[i]; 
for(j=i+1; j<maxEachDist.size(); j++)
if(min>maxEachDist[j])
{
min = maxEachDist[j];
l = j;
}


temp = maxEachDist[i];
maxEachDist[i] = maxEachDist[l];
maxEachDist[l] = temp;


tempVet = dst[i];
dst[i] = dst[l];
dst[l] = tempVet;
}


return dst;
}




//进行合并
vector<doubleVector> Union(vector<doubleVector> mCenter, vector<doubleVector> sortDist)
{
int i[connectNum], j[connectNum];
int m, n, delNum=0;
vector<doubleVector> newCenter;
vector<int> del;
doubleVector temp;


newCenter = mCenter;


//可联合数量
for(m=0; m<connectNum; m++)
for(n=0; n<dimNum; n++)
if(sortDist[m][n]<connectVar)
{
delNum++;
break;
}


//进行联合
for(m=0; m<delNum; m++)
{
i[m] = sortDist[m][dimNum];
j[m] = sortDist[m][dimNum+1];


for(n=0; n<dimNum; n++)
temp.push_back((i[m]*mCenter[i[m]][n]+j[m]*mCenter[j[m]][n])/(i[m]+j[m]));


newCenter.push_back(temp);
}


//避免重复删除
for(m=0; m<delNum; m++)
del.push_back(i[m]);

for(n=0; n<delNum; n++)
{
if(del[n]==j[n])
continue;
else
del.push_back(j[n]);
}



  for(m=0; m<del.size(); m++)
  newCenter[del[m]].clear();


for(m=0; m<newCenter.size(); )
{
if(newCenter[m].empty())
newCenter.erase(newCenter.begin()+m);
else
m++;
}

return newCenter;
}




//结果输出
void Output(vector<clusterVector> cluster)
{
int i, j, k;


for(i=0; i<cluster.size(); i++)
{
printf("\n类聚%d :\n", i+1);
for(j=0; j<cluster[i].size(); j++)
printf("%lf  %lf  %lf\n", cluster[i][j][0], cluster[i][j][1], cluster[i][j][2]);
}
}