您的位置:首页 > 其它

模糊C均值聚类(FCM)算法

2018-02-12 11:29 330 查看
本代码算法用例为鸢尾花数据集合;
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]
<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]]
+j[m]*mCenter[j[m]]
)/(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
==j
)
continue;
else
del.push_back(j
);
}

  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]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: