本代码算法用例为鸢尾花数据集合;
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
typedef vector
void ISODATA(vector
vector
int getClusterNum(vector
double getEUCdis(doubleVector t1, doubleVector t2); //计算欧式距离
doubleVector get_wMean(clusterVector cluster); //计算均值向量
doubleVector averageDist(doubleVector mCenter, clusterVector cluster); //计算Wi中所有样本距其相应聚类中心的平均距离
doubleVector allAvgDist(vector
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
vector
void Output(vector
//主函数
void main()
{
vector
srcInf = getInf();
ISODATA(srcInf);
}
//迭代开始引擎
void ISODATA(vector
{
int c;
int i, j;
int iter=1;
int lable;
vector
vector
vector
vector
doubleVector all_AvgDis;
vector
vector
vector
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
chooseNum = rand()%(int)(srcInf.size()/cNum)+i*(srcInf.size()/cNum);
for(j=0; j
}
//根据距离归类
step2:
if(cluster.empty()==NULL)
cluster.clear();
cluster.resize(2*cNum);
for(i=0; i
lable = getClusterNum(mCenter, srcInf[i]);
cluster[lable].push_back(srcInf[i]);
}
//舍弃过小的类
step3:
for(i=0; i
if(cluster[i].size()
cluster.erase(cluster.begin()+i);
if(i
}
else
i++;
}
c = mCenter.size();
//更新均值向量
step4:
if(wMean.empty()==NULL)
wMean.clear();
for(i=0; i
//获取各平均距离
step5:
if(avgDist.empty()==NULL)
avgDist.clear();
for(i=0; 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
//计算标准偏差中偏差最大值
step9:
if(devMax.empty()==NULL)
devMax.clear();
for(i=0; i
//进行分裂
step10:
for(i=0; 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
for(j=i+1; 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
{
int i=1;
vector
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
return sqrtf(distance);
}
//根据初始中心进行归类
int getClusterNum(vector
{
double Dis;
double minDis = getEUCdis(mCenter[0], srcInf);
int i, lable=0;
for(i=1; i
Dis = getEUCdis(mCenter[i], srcInf);
if(Dis
minDis = Dis;
lable = i;
}
}
return lable;
}
//计算均值向量
doubleVector get_wMean(clusterVector cluster)
{
doubleVector wMean;
double temp[dimNum];
int i, j;
for(i=0; i
for(i=0; i
for(i=0; i
wMean.clear();
for(i=0; i
return wMean;
}
//计算类聚中心m[i]的平均距离
doubleVector averageDist(doubleVector mCenter, clusterVector cluster)
{
int i, j;
doubleVector avgDist;
double temp[dimNum]={0};
for(i=0; i
for(i=0; i
avgDist.clear();
for(i=0; i
return avgDist;
}
//计算所以样本距其相应的聚类中心的平均值
doubleVector allAvgDist(vector
{
int i, j;
doubleVector allAvg;
double temp[dimNum]={0};
for(i=0; i
for(i=0; i
allAvg.clear();
for(i=0; i
return allAvg;
}
//计算每一个聚类的标准偏差
doubleVector getDeviation(doubleVector mCenter, clusterVector cluster)
{
doubleVector dst;
int i, j;
double temp[dimNum]={0};
for(i=0; i
dst.clear();
for(i=0; 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
return max;
}
//进行分裂
doubleVector clusterSplit(doubleVector wMean, double sigma)
{
int i;
doubleVector newMean;
double temp;
newMean.clear();
for(i=0; 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
dist.push_back(x);
dist.push_back(y);
return dist;
}
//按距离进行排序
vector
{
int i, j, l;
vector
doubleVector maxEachDist;
double temp;
doubleVector tempVet;
double min;
dst = eachDist;
//寻找每组中最大的距离
maxEachDist.clear();
for(i=0; i
//排序
for(i=0; i
l=i;
min = maxEachDist[i];
for(j=i+1; 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
{
int i[connectNum], j[connectNum];
int m, n, delNum=0;
vector
vector
doubleVector temp;
newCenter = mCenter;
//可联合数量
for(m=0; m
delNum++;
break;
}
//进行联合
for(m=0; m
i[m] = sortDist[m][dimNum];
j[m] = sortDist[m][dimNum+1];
for(n=0; n
newCenter.push_back(temp);
}
//避免重复删除
for(m=0; m
for(n=0; n
if(del[n]==j[n])
continue;
else
del.push_back(j[n]);
}
for(m=0; m
for(m=0; m
if(newCenter[m].empty())
newCenter.erase(newCenter.begin()+m);
else
m++;
}
return newCenter;
}
//结果输出
void Output(vector
{
int i, j, k;
for(i=0; i
printf("\n类聚%d :\n", i+1);
for(j=0; j
}
}