ISODATA算法.docx
《ISODATA算法.docx》由会员分享,可在线阅读,更多相关《ISODATA算法.docx(25页珍藏版)》请在冰豆网上搜索。
ISODATA算法
ISODATA算法汇报文档
一.算法介绍
1.背景
ISODATA(迭代自组织数据分析算法)来自模糊数学领域,是统计模式识别中非监督动态聚类算法的一种。
在许多科学实验、经济管理和日常生活中,往往需要对某些指标(或事物)按一定的标准(相似的程度、亲疏关系等)进行分类处理。
例如,根据生物的某些形态对其进行分类,图像识别中对图形的分类等。
这种对客观事物按一定要求和规律进行分类的数学方法主要就是聚类分析法,聚类分析是数理统计中研究“物以类聚”的一种多元分析方法,而模糊聚类分析法是通过数学工具根据事物的某些模糊性质进行定量地确定、合理地分型划类的数学方法。
2、算法基本思想
J.C.Bezdek在普通分类基础上,利用模糊集合的概念提出了模糊分类问题。
认为被分类对象集合X中的样本x[i]以一定的隶属度属于某一类,即所有的样本都分别以不同的隶属度属于某一类。
因此,每一类就被认为是样本集X上的一个模糊子集,于是,每一种这样的分类结果所对应的分类矩阵,就是一个模糊矩阵。
ISODATA聚类方法预先确定样本应该分成几类,从先给出的一个初始分类出发,根据目标函数,用数学迭代计算的方法反复修改模糊矩阵,直到合理为止。
3、算法基本原理
设有限样本集(论域)X={X1,X2,…Xn},每一个样本有s个指标,Xj=(xj1,xj2,…xjs),j=1,2,…n.
及样本的特征矩阵:
欲把它分为c类(2其满足三个条件:
(i=1,2,…c;j=1,2,…n)
定义c个聚类中心向量聚类中心V={V1,V2,…Vc}.其中Vi=(vi1,vi2,…vis},i=1,2,…c.
第i类的中心vi即人为假想的理想样本,它对应的s个指标值是该类样本所对应的指标值的平均值:
定义矩阵U=[uij]c×n的全体构成样本集X分成c类的软划分空间:
其中,uij表示第j个样本Xj隶属于第i类的隶属度。
构造目标泛函:
其中:
‖xj-vi‖2表示第j个样本与第i类中心之间欧氏距离的平方;Jm(U,V)表示所有待聚类样本与所属类的聚类中心之间距离的平方和。
为了确定最佳分类结果,就是寻求最佳划分矩阵U和对应的聚类中心V,使Jm(U,V)达到极小,即Jm(U3,V3)=min{Jm(U,V),U∈Mfc}。
Dunn证明了求上述泛函的极小值的问题可解,Bezdek给出了当m≥1且xk≠vi时迭代算法。
4.具体算法步骤
(1)给定控制参数
K:
预期的聚类中心数目。
θn:
每一聚类中最少的样本数目,如果少于此数就不能作为一个独立的聚类。
θs:
一个聚类域中样本距离分布的标准差(阈值)。
θc:
两个聚类中心之间的最小距离,如果小于此数,两个聚类合并。
L:
每次迭代允许合并的最大聚类对数目。
I:
允许的最多迭代次数。
给定n个文档集合D={d1,d2,⋯,dn},令J=1(迭代次数),预选c个起始聚合中心,Zj(J),j=1,2⋯,c。
(2)计算每个样本与聚合中心距离:
D(xk,Zj(J))。
若:
D(xk,Zj(J))=min
j=1,2⋯,c.{D(xk,Zj(J)),k=1,2,⋯,n},则:
xk∈wi。
把全部样本划分到c个聚合中去,且nj表示各子集Xj中的样本数目。
(3)判断:
若nj<θn,j=1,2⋯,c则舍去子集Xj,c=c-1,返回
(2)。
(4)计算修改聚合中心:
j=1,3,⋯c。
(5)计算类内距离平均值Dj:
(6)计算类内总平均距离D(全部样本对其相应聚类中心的总平均距离):
(7)判别分裂、合并及迭代运算等步骤。
a1如迭代运算次数已达I次,即最后一次迭代,置θc=0,跳到
(1),运算结束。
b1如cFK2,即聚类中心的数目等于或不到规定值的一半,则转(8),将已有的聚类分裂。
c1如迭代运算的次数是偶数,或cE2K,则不进行分裂,跳到(11),若不符合上述2个条件,则进入(8),进行分裂处理。
(8)计算每个聚合的标准偏差向量:
式中:
xi——x的第i个分量;
Zji——Zj的第i个分量;
d——维数。
(9)求出每个聚合的最大标准偏差分量σjmax:
则把该集合分为2个新的聚合,聚合中心分别为:
令:
c=c+1,J=J+1返回
(2)
其中,K的选择很重要,应使Xj中的样本到Z+j(J)和Z-j(J)的距离不同,但又使样本全部在这2个集合中。
(11)计算两两聚合中心间的距离Dij:
(12)比较Dij与θc,并把小于θc的Dij按递增次序排队:
Di1j1(13)考查(12)中的不等式,对每一个DiLjL,相应有2个聚类中心ZiL和ZjL,假使在同一次迭代中,还没把ZiL和ZjL合并,则把两者合并,合并后中心为:
令c=c+1
(14)若J
(1),不修改参数返回
(2),否则J=I,算法结束。
注意:
(8)—(10)步为分裂,(11)—(13)为合并。
分裂过程中,如果聚合的标准偏差的某一个分量大于给定的参数θs,则被分裂成2个聚合;如有2个以上的聚合的标准偏差满足条件,则要重复执行(10),使它们均分裂成2个聚合。
合并过程中,不难看出,在一次迭代过程中,最多合并的聚合对数必然小于给定的参数L。
5.算法流程图:
二.程序实现
采用编程语言:
C语言
编译环境:
VC++6.0
使用样本(如截图);样本集大小为10,维数为3
以下为各参数声明:
intc;//预期的类数
intNc;//初始聚类中心个数
inttheta_min;//每类中允许的最少模式数(小于此数不可单独成类)
floattheta_top;//类内个分量分布的标准差上限(大于此数就分裂)
floatdis_min;//两类中心间的最小距离下限(小于此数两类合并)
intL;//在每次迭代中可以合并的类的最大对数
intI;//最多迭代次数
structPatternx[N];/全部模式
structSortw[N];//全部类
floatD[MAXNUM][MAXNUM];//各类对中心间的距离
floatdis;//总体平均距离
intIp=0;//记录迭代次数
inti;j;//循环变量
以下为程序用到的调用函数:
voidInit();
voidProcess();
voidInitCenter();
voidClustering();
floatDistance(structPatternx1,structPatternx2);
structSortInsert(structPatterna,structSortb);
intCombinBytheta_min();
voidCalParameter();
structPatternCalCenter(structSorta);
floatCal_D();
voidCalSigma();
intSplit();
voidCalCenterDis();
intCombinBydis_min();
intCombin(structPatterna,structSortb);
voidPrintSort();
程序运行界面截图:
程序运行结果示例:
三.过程收获
这是我第一次在VC的环境下写超过100行的程序。
虽然在用C#做网络实验的时候OOP的东西接触过,但由于没有C++的基础,对C++的源码只停留在可以看懂的水平,所以在短时间内掌握C++并用它实现算法,我还是觉得难以驾驭,所以决定使用C语言。
而C语言在去年考过三级后就再也没碰过,很多细节已经记不清了,况且当时学得就不深,没有写过逻辑性太复杂的程序,所以不管是OOP还是C都显得半生不熟(⊙﹏⊙b汗!
)。
因此,在完成算法的一半时间内都在和VC磨合,回忆细节,找编程感觉,以致拖到今天才完成,再次⊙﹏⊙b汗!
由于我搜索到并加以参考的源码是用C++实现的,所以我的工作首先就是理解了算法的基本流程和实现思路,然后改用C语言实现。
程序流程基本没变,但重写了大部分调用函数,来保证传值与传址。
关键的一点就是要切实搞清楚内部逻辑关系,清楚算法的每个细节,否则移植的过程中一旦出现error都无从下手。
程序很长,培养了我的耐心。
调试过程中出现过死循环(还是在比较靠前的位置,郁闷!
),我采用的是一段段屏蔽程序的方法,在一系列不同的区段设置打印输出语句,显示中间过程数据,用于发现错误并检验修改结果。
过程很漫长,再次锻炼了我的耐心~纠结时间比较长的是Insert函数。
另外在实现过程中尽力回避了我容易出错的的指针。
考虑到数据结构和C++用指针都较多,这一部分还需强化。
其他关于程序本身书写规范方面碰到的问题不再赘述,相比于逻辑上的问题和移植时的问题,那都是小问题。
可以靠系统帮助改正。
最郁闷的时候就是没有error结果却不对……+_+
上面那个程序流图,本来很不甘心用截图的,我下了一个visio,结果……我画不好⊙﹏⊙b汗!
!
练好了再画吧……
写程序是苦差,尤其是对眼睛来说。
但是(肯定要有但是啊~HOHO~),在看到编译连接后没有error时,在看到输完最后一个参数回车后显示了正确的结果时,那种心情~不是一个happy可以形容的~
PS:
OOP相比还是方便一点,C#是可以把人宠坏的,VS是会2009-8-22009-8-2让人变懒的。
我还是多学点底层的才是王道~后悔没有早一点接触数模,感觉那个挺强大的~再次对设计算法的人表示我的膜拜!
Istillhavealongwaytogo~!
#defineMAXNUM100//最大模式个数
#defineMAXDIM10//最大模式维数
#defineK0.5//分裂时使用
#defineMAXDOUBLE1.0e20//最大双精度值
#defineN10//实际模式个数
#defineDIM3//实际模式维数
#include
#include
#include
#include
#include
structPattern//模式结构体
{
intn;//模式序号
floats[MAXDIM];//模式数据
};
structSort//类结构体
{
structPatternz;//类心
intn;//类中包含的模式数目
floatavg_d;//模式到类心的平均距离
structPatterny[MAXNUM];//模式
floatsigma[MAXDIM];//三个分量的标准差
intmax;//用于记录类内距离标准差矢量最大的分量下标
floatsigma_max;//临时保存类内距离标准差矢量最大值
};
structPatternInitPattern(inti,floata,floatb,floatc)//对样品模式进行初始化
{
structPatterntemp;
temp.n=i;
temp.s[0]=a;
temp.s[1]=b;
temp.s[2]=c;
returntemp;
}
//以下为各参数声明
intc;//预期的类数
intNc;//初始聚类中心个数
inttheta_min;//每一类中允许的最少模式数(小于此数不可单独成类)
floattheta_top;//类内个分量分布的标准差上限(大于此数就分裂)
floatdis_min;//两类中心间的最小距离下限(小于此数两类合并)
intL;//在每次迭代中可以合并的类的最大对数
intI;//最多迭代次数
structPatternx[N];//全部模式
structSortw[N];//全部类
floatD[MAXNUM][MAXNUM];//各类对中心间的距离
floatdis;//总体平均距离
intIp=0;//记录迭代次数
inti;j;//循环变量
//以下为程序用到的调用函数
voidInit();
voidProcess();
voidInitCenter();
voidClustering();
floatDistance(structPatternx1,structPatternx2);
structSortInsert(structPatterna,structSortb);
intCombinBytheta_min();
voidCalParameter();
structPatternCalCenter(structSorta);
floatCal_D();
voidCalSigma();
intSplit();
voidCalCenterDis();
intCombinBydis_min();
intCombin(structPatterna,structSortb);
voidPrintSort();
voidmain()
{
Init();
printf("\n******************ISODATA算法演示程序**************************");
printf("WrittenBy:
王慧(BME0701U200713005)\n");
printf("本实验使用样本集如下:
\n");
x[0]=InitPattern(0,0.50,0.50,0.50);
x[1]=InitPattern(1,5.40,2.00,6.00);
x[2]=InitPattern(2,1.10,1.00,2.90);
x[3]=InitPattern(3,2.00,1.30,5.00);
x[4]=InitPattern(4,1.90,2.10,3.30);
x[5]=InitPattern(5,1.10,2.10,3.10);
x[6]=InitPattern(6,4.00,4.00,2.00);
x[7]=InitPattern(7,5.40,2.00,1.00);
x[8]=InitPattern(8,4.70,2.30,5.10);
x[9]=InitPattern(9,6.00,5.00,4.00);
for(i=0;i{
printf("\tX(%d):
(",x[i].n);
for(j=0;jprintf("%3.2f,",x[i].s[j]);
printf("%3.2f);\n",x[i].s[j]);
}
Process();//程序最重要函数,所有算法步骤均在其中
printf("********************演示程序完毕,谢谢使用!
************************");
printf("WrittenBy:
王慧(BME0701U200713005)\n");
system("pause");
}
voidInit()//对两结构体变量初始化(赋零值)
{
inti,j,k,l;
for(i=0;i{
x[i].n=0;
w[i].n=0;
w[i].avg_d=0;
w[i].max=0;
w[i].sigma_max=0;
w[i].z.n=0;
for(j=0;j{
x[i].s[j]=0;
w[i].sigma[j]=0;
w[i].z.s[j]=0;
}
for(k=0;k{
w[i].y[k].n=0;
for(l=0;lw[i].y[k].s[l]=0;
}
}
for(i=0;ifor(j=0;jD[i][j]=0;
}
voidInitCenter()//选定初始聚类中心
{
inti,j,k,l;
intnum=N;
intno[MAXNUM];
for(i=0;ino[i]=i;
srand((unsigned)time(NULL));//生成随机数种子
for(j=0;j{
intk=rand()%num;
w[j].z=x[no[k]];
w[j].z.n=0;
for(l=k;lno[l]=no[l+1];
num--;
}
}
voidClustering()//依最小距离原则将全部模式归类
{
floattemp=0.0,min=MAXDOUBLE;
inti,j,l=0;
for(j=0;j{
w[j].n=0;
w[j].z.n=0;
}
for(i=0;i{
min=MAXDOUBLE;
l=0;
for(j=0;j{
temp=Distance(x[i],w[j].z);
if(min>temp)
{
min=temp;
l=j;
}
}
w[l]=Insert(x[i],w[l]);
}
}
floatDistance(structPatternx1,structPatternx2)//计算两个模式距离的函数
{
inti;
floattemp=0.0;
for(i=0;itemp+=(x1.s[i]-x2.s[i])*(x1.s[i]-x2.s[i]);
returnsqrt(temp);
}
structSortInsert(structPatterna,structSortb)//将某模式插入对应类
{
b.n++;
b.y[b.n-1]=a;
returnb;
}
intCombinBytheta_min()//依据theta_min判断合并,若类w[j]中模式数小于theta_min,取消类心,Nc=Nc-1,转至step2:
{
intj=0,k;
do
{
if(w[j].n{
for(k=j;kw[k].z=w[k+1].z;
Nc--;
return1;
}
j++;
}while(jreturn0;
}
structPatternCalCenter(structSorta)//计算类心
{
inti,j;
structPatterntemp;
for(i=0;ifor(j=0;jtemp.s[j]+=a.y[i].s[j];
for(i=0;itemp.s[i]/=a.n;
returntemp;
}
floatCal_D(structSorta,structPatternb)//计算各模式到类心的平均距离
{
inti;
a.avg_d=0.0;
for(i=0;ia.avg_d+=Distance(a.y[i],b);
a.avg_d/=a.n;
returna.avg_d;
}
voidCalParameter()//计算分类后参数:
各类中心、类内平均距离以及总体平均距离
{
inti;
structPatterntemp;
dis=0.0;
for(i=0;i{
temp=CalCenter(w[i]);
dis+=w[i].n*Cal_D(w[i],temp);
}
dis/=N;
}
voidCalSigma()//计算各类类内距离的标准差矢量
{
inti,j,k;
for(j=0;j{
floattemp=0.0;
for(k=0;k{
for(i=0;i{
structPatternz;
z=CalCenter(w[j]);
temp+=(w[j].y[i].s[k]-z.s[k])*(w[j].y[i].s[k]-z.s[k]);
}
w[j].sigma[k]=sqrt(temp/w[j].n);
if(w[j].sigma_max{
w[j].sigma_max=w[j].sigma[k];
w[j].max=k;
}
}
}
}
intSplit()//判断分裂
{
inti,j,l;
for(j=0;j{
floatsigma_temp=w[j].sigma_max;
if((w[j].avg_d>dis)&&(w[j].n>2*(theta_min+1))||(Nc<=c/2))
{
i=w[j].max;
for(l=Nc;l>j;l--)
w[l].z=w[l-1].z;
w[j].z.s[i]-=K*sigma_temp;
w[j+1].z.s[i]+=K*sigma_temp;
Nc++;
return1;
}
}
return0;
}
voidCalCenterDis()//计算各类对中心间的距离
{
inti,j;
for(i=0;ifor(j=i+1;jD[i][j]=Dist