📄 cluster.cpp
字号:
GetFeature();
int distype;//距离的形式(欧氏、余弦...)
int times;//max loop number
int i,j;
DlgInfor mDlgInfor;
mDlgInfor.ShowInfor(4);
if (mDlgInfor.DoModal()==IDOK)
{
distype=mDlgInfor.m_DisType;
times=mDlgInfor.m_Times;
centernum=mDlgInfor.m_CenterNum;
}
else return;
BOOL change=true;//退出标志,false时表示样品所属类别不再变化,中止计算
int counter=0;//记录当前已经循环的次数
double distance;//到各中心的距离
distance=MAX;
m_center=new Center[centernum];
for ( i=0;i<patternnum;i++)
m_pattern[i].distance=MAX;
for ( i=0;i<centernum;i++)//初始化,前centernum个模版各自分为一类
{
m_pattern[i].category=i+1;
m_pattern[i].distance=0;
for ( j=0;j<N*N;j++)
m_center[i].feature[j]=m_pattern[i].feature[j];
m_center[i].index=i+1;
}
while (change && counter<times)
{
counter++;
change=false;
for( i=0;i<patternnum;i++)//对所有样品重新归类
{
//计算第i个模式到各个聚类中心的最小距离,
int index=1;
distance=MAX;
for (int j=0;j<centernum;j++)
if (distance>GetDistance(m_pattern[i],m_center[j],distype))
{
distance=GetDistance(m_pattern[i],m_center[j],distype);
index=j;//找到最小距离,是到第index个聚类中心的距离
}
//比较原中心号与新中心号
//相同:更新距离。
//不同:1,新距离小,则归入新中心,更新距离,重新计算前后两个聚类中心模式
//2,新距离大于原距离,不处理;
//counter++
if (m_pattern[i].category==m_center[index].index)//属于原类
{
m_pattern[i].distance=distance;
}
else//不属于原类
{
int tpcenter=m_pattern[i].category;//记录原类号
m_pattern[i].category=m_center[index].index;//归入新类
m_pattern[i].distance=distance;
if(tpcenter!=0)
{
for (int k=0;k<centernum;k++)
if (m_center[k].index==tpcenter)
CalCenter(&m_center[k]);//计算原属类中心
}
CalCenter(&m_center[index]);//计算新属类中心
change=true;
}
}
}//end of while
delete []m_center;
}
/************************************************************
*函数名称 ISODATA()
*参数 void
*返回值 void
*函数功能 用ISODATA方法对全体样品进行分类
************************************************************/
void CCluster::ISODATA()
{
GetFeature();
int i,j;
int distype;
int times;//迭代的最多次数,用户输入
int precenternum;//当前类数
double T;//两类中心的最小距离,小于该阈值将合并
double equation;//类内方差阈值
double *avedistance;//avedistance[i]:第i+1类内平均距离,i=0,1,...,centernum.
double allavedis;//全部模式样本中心平均距离
double minous,maxous,mincos,maxcos,minbcos,maxbcos,mintan,maxtan;
minous=MAX; mincos=MAX; minbcos=MAX; mintan=MAX;
maxous=0; maxcos=0; maxbcos=0; maxtan=0;
//计算四种距离模式的参考值
for ( i=0;i<patternnum-1;i++)
for ( j=i+1;j<patternnum;j++)
{
if (minous>GetDistance(m_pattern[i],m_pattern[j],1))
minous=GetDistance(m_pattern[i],m_pattern[j],1);
if (maxous<GetDistance(m_pattern[i],m_pattern[j],1))
maxous=GetDistance(m_pattern[i],m_pattern[j],1);
if (mincos>GetDistance(m_pattern[i],m_pattern[j],2))
mincos=GetDistance(m_pattern[i],m_pattern[j],2);
if (maxcos<GetDistance(m_pattern[i],m_pattern[j],2))
maxcos=GetDistance(m_pattern[i],m_pattern[j],2);
if (minbcos>GetDistance(m_pattern[i],m_pattern[j],3))
minbcos=GetDistance(m_pattern[i],m_pattern[j],3);
if (maxbcos<GetDistance(m_pattern[i],m_pattern[j],3))
maxbcos=GetDistance(m_pattern[i],m_pattern[j],3);
if (mintan>GetDistance(m_pattern[i],m_pattern[j],4))
mintan=GetDistance(m_pattern[i],m_pattern[j],4);
if (maxtan<GetDistance(m_pattern[i],m_pattern[j],4))
maxtan=GetDistance(m_pattern[i],m_pattern[j],4);
}
//求所有样品总方差
double cen[N*N],equ[N*N];
for (i=0; i<N*N; i++)
{
cen[i]=0;
equ[i]=0;
}
for (i=0;i<patternnum;i++)//所有样品特征累加
for (j=0;j<N*N;j++)
cen[j]+=m_pattern[i].feature[j];
for (i=0;i<N*N;i++)//求所有样品特征均值
cen[i]=cen[i]/(double)patternnum;
for (i=0;i<patternnum;i++)//总方差
for (j=0;j<N*N;j++)
equ[j]+=(m_pattern[i].feature[j]-cen[j])*(m_pattern[i].feature[j]-cen[j]);
for (i=0;i<N*N;i++)//均方差
equ[i]=sqrt(equ[i]/(double)patternnum);
double minequ=MAX;
double maxequ=0.0;
//求均方差中的最大最小值
for (i=0;i<N*N;i++)
{
if (minequ>equ[i])
minequ=equ[i];
if (maxequ<equ[i])
maxequ=equ[i];
}
DlgInfor mDlgInfor;
//输出到对话框
mDlgInfor.ShowInfor(minous,maxous,mincos,maxcos,minbcos,maxbcos,mintan,maxtan,minequ,maxequ);//OUTPUT EQUATIONOUT!!!
if (mDlgInfor.DoModal()==IDOK)
{
distype=mDlgInfor.m_DisType;
T=mDlgInfor.m_T;
times=mDlgInfor.m_Times;
equation=mDlgInfor.m_EquationIn;
centernum=mDlgInfor.m_CenterNum;
}
else return;
//所有样品各归一类
precenternum=centernum;
m_center=new Center[precenternum];
for ( i=0;i<precenternum;i++)
{
m_pattern[i].category=i+1;
for (j=0;j<N*N;j++)
m_center[i].feature[j]=m_pattern[i].feature[j];
m_center[i].index=i+1;
m_center[i].patternnum=1;
}
int counter=0;//循环次数
avedistance=new double[precenternum];
while (++counter<times)
{
for ( i=0;i<patternnum;i++)//把所有样品重新归类
{
double td=MAX;
int index=0;
for (int j=0;j<precenternum;j++)
if (td>GetDistance(m_pattern[i],m_center[j],distype))
{
td=GetDistance(m_pattern[i],m_center[j],distype);
index=j;
}
m_pattern[i].category=m_center[index].index;
}
//修正各中心
for (i=0;i<precenternum;i++)
CalCenter(&m_center[i]);
for (i=0; i<precenternum;i++)
{
if (m_center[i].patternnum==0)
{
for(j=i; j<precenternum-1; j++)
m_center[j]=m_center[j+1];
precenternum--;
}
}
//计算各类距中心平均距离
for (i=0;i<centernum;i++)
avedistance[i]=0.0;//初始化
allavedis=0; //全部样本平均距离
for (i=0;i<precenternum;i++)
{
int num=0;//类中成员个数
double dis;
dis=0.0;
for ( j=0;j<patternnum;j++)
{
if (m_pattern[j].category==i+1)
{
++num;
dis+=GetDistance(m_pattern[j],m_pattern[i],distype);
}
}
allavedis+=dis;
avedistance[i]=(double)(dis/(double)num);
}
allavedis/=patternnum;
if ((precenternum>=2*centernum) || ((counter%2)==0) && (precenternum>(int)(centernum/2+0.5)))//合并
{
//找到距离最近的两个类
double td=MAX;
int ti,tj;
for( i=0;i<precenternum;i++)
for ( j=i+1;j<precenternum;j++)
{
double tdin;
tdin=GetDistance(m_center[i],m_center[j],distype);
if (td<tdin)
{
td=tdin;
ti=i;
tj=j;
}
}
//判断是否要合并
if(td<T)//合并
{
for ( i=0;i<patternnum;i++)
{
if (m_pattern[i].category==m_center[tj].index)
m_pattern[i].category=m_center[ti].index;
if (m_pattern[i].category>m_center[tj].index)
m_pattern[i].category--;
}
CalCenter(&m_center[ti]);
for (i=tj;i<precenternum-1;i++)
{
m_center[i]=m_center[i+1];
m_center[i].index--;
}
precenternum--;
}
}//end 合并
else//分裂
{
double **mequation;//标准差
int ti,tj;//记录最大标准差出现位置,第ti+1号类的第tj+1位。ti=0,1,...,precenternum-1.
mequation= new double *[precenternum];
for (i=0;i<precenternum;i++)
{
mequation[i]=new double[N*N];
for (j=0;j<N*N;j++)
mequation[i][j]=0.0;
}
//计算标准差
for ( i=0;i<precenternum;i++)
{
for ( j=0;j<patternnum;j++)
if (m_pattern[j].category==m_center[i].index)
{
for (int k=0;k<N*N;k++)
mequation[i][k]+=(m_pattern[j].feature[k]-m_center[i].feature[k])*(m_pattern[j].feature[k]-m_center[i].feature[k]);
}
for (int k=0;k<N*N;k++)
mequation[i][k]=sqrt(mequation[i][k]/m_center[i].patternnum);
}
//找最大标准差
ti=0;
tj=0;
for (i=0;i<precenternum;i++)
for ( j=0;j<N*N;j++)
if(mequation[i][j]>mequation[ti][tj])
{
ti=i;tj=j;
};
//判断是否要分裂
if (mequation[ti][tj]>equation)//大于给定阈值
{
if (avedistance[ti]>allavedis )
//类平均距离大于总平均距离 分裂
{
precenternum++;
Center *tempcenter;
tempcenter=new Center [precenternum];
for (i=0;i<precenternum-1;i++)
tempcenter[i]=m_center[i];
tempcenter[precenternum-1].index=precenternum;
for (j=0;j<N*N;j++)
tempcenter[precenternum-1].feature[j]=m_center[ti].feature[j];
tempcenter[precenternum-1].feature[tj]-=0.5*mequation[ti][tj];
tempcenter[ti].feature[tj]+=0.5*mequation[ti][tj];
delete []m_center;
m_center=tempcenter;
}
}
delete []mequation;
}//end 分裂
}//end while(1)*/
delete []avedistance;
delete []m_center;
}
/************************************************************
*函数名称 Mohujulei()
*参数 void
*返回值 void
*函数功能 用模糊聚类方法对全体样品进行分类
************************************************************/
void CCluster::FuzzyCluster()
{
GetFeature();//获得所有样品特征
double *dis, *tempdis;
double dismax;
int i,j;
int distype;
dismax=0;
dis=new double [patternnum*patternnum];//模糊系数矩阵
tempdis=new double [patternnum*patternnum];
DlgFuzzyDistance dfd;
if (dfd.DoModal()==IDOK)
{
distype=dfd.mfuzzydistance;
}
else
return;
//得到初始模糊距离
for ( i=0; i<patternnum; i++)
for (j=0; j<patternnum; j++)
{
dis[i*patternnum+j]=GetFuzzyDistance(m_pattern[i],m_pattern[j],distype);//distype
}
//构造等价类
bool flag;
flag=true;
while (flag)
{
flag=false;
for ( i=0; i<patternnum; i++)
for ( j=0; j<patternnum; j++)
if (i==j)//对角线为1
tempdis[i*patternnum+j]=1;
else
tempdis[i*patternnum+j]=GetDistance(dis,i,j);
for ( i=0; i<patternnum; i++)
{
for ( j=0; j<patternnum; j++)
if ((tempdis[i*patternnum+j]-dis[i*patternnum+j])*(tempdis[i*patternnum+j]-dis[i*patternnum+j])>0.000001)//(tdis[i][j]!=dis[i][j])
{
flag=true;
break;
}
if (flag)
break;
}
for ( i=0; i<patternnum*patternnum; i++)
dis[i]=tempdis[i];
}
//输出模糊矩阵
CString ts,sout;
//第一行标号1,2,。。。,patternnum。
sout.Insert(sout.GetLength()," \t");
for (i=1; i<=patternnum; i++)
{
ts.Format("%d \t",i);
sout.Insert(sout.GetLength(),ts);
}
sout.Insert(sout.GetLength(),"\n\n");
for (i=0; i<patternnum; i++)
{
//每列开头标号
ts.Format("%d \t",i+1);
sout.Insert(sout.GetLength(),ts);
//输出模糊系数矩阵
for(j=0; j<patternnum; j++)
{
ts.Format("%0.3f\t",dis[i*patternnum+j]);
sout.Insert(sout.GetLength(),ts);
if ((j+1)%patternnum==0)
sout.Insert(sout.GetLength(),"\n\n\n");
}
}
MessageBox(NULL,sout,"模糊矩阵",MB_OK);
delete []tempdis;
double *xishu=new double [patternnum*patternnum];
for(i=0; i<patternnum*patternnum; i++)
xishu[i]=-1;
int pointer=0;
//记录模糊系数矩阵中不同的系数
for ( i=0; i<patternnum; i++)
for ( j=i; j<patternnum; j++)
{
bool done=false;
for (int k=0; k<pointer; k++)
{
if ((xishu[k]-dis[i*patternnum+j])*(xishu[k]-dis[i*patternnum+j])<0.000001)
{
done=true;
break;
}
}
if (!done)
{
xishu[pointer]=dis[i*patternnum+j];
pointer++;
}
}
for(i=0; i<pointer-1; i++)//对阈值由小到大排序
for (j=0; j<pointer-i-1; j++)
{
if (xishu[j]>xishu[j+1])
{
double temp=xishu[j];
xishu[j]=xishu[j+1];
xishu[j+1]=temp;
}
}
CString s,str;
for (i=0; i<pointer; i++)
{
s.Format("%0.4f ",xishu[i]);
str.Insert(str.GetLength(),s);
}
delete []xishu;
//用户输入聚类阈值
double yz;
DlgMohu mohu;
mohu.m_Mohuxishu=str;
if (mohu.DoModal()==IDOK)
{
yz=mohu.m_Mohuyuzhi;
}
else return;
int *result;
//根据阈值输出聚类结果
result=new int [patternnum*patternnum];
for (i=0; i<patternnum*patternnum; i++)
if (dis[i]>=yz)
result[i]=1;
else
result[i]=0;
//分类后输出
//第一行标号
sout="";
sout.Insert(-1,"每行中\"1\"对应的列为同一类");
sout.Insert(sout.GetLength(),"\n\n");
sout.Insert(sout.GetLength()," \t");
for (i=1; i<=patternnum; i++)
{
ts.Format("%d \t",i);
sout.Insert(sout.GetLength(),ts);
}
sout.Insert(sout.GetLength(),"\n\n");
for (i=0; i<patternnum; i++)
{
//每列开头标号
ts.Format("%d \t",i+1);
sout.Insert(sout.GetLength(),ts);
for(j=0; j<patternnum; j++)//首行为原模糊系数
{
ts.Format("%0.3f\t",dis[i*patternnum+j]);
sout.Insert(sout.GetLength(),ts);
if ((j+1)%patternnum==0)
sout.Insert(sout.GetLength(),"\n");
}
sout.Insert(sout.GetLength()," \t");
for(j=0; j<patternnum; j++)//次行为根据阈值修改后的系数“1”或“0”
{
ts.Format("%d\t",result[i*patternnum+j]);
sout.Insert(sout.GetLength(),ts);
if ((j+1)%patternnum==0)
sout.Insert(sout.GetLength(),"\n\n");
}
}
MessageBox(NULL,sout,"分类前后的矩阵对照",MB_OK);
centernum=0;
for (i=0; i<patternnum; i++)//按照阈值分类
for (j=i; j<patternnum; j++)
{
if (result[i*patternnum+j]==1)
{
if (m_pattern[i].category!=0)
m_pattern[j].category=m_pattern[i].category;
else if (m_pattern[j].category!=0)
m_pattern[i].category=m_pattern[j].category;
else
{
centernum++;
m_pattern[j].category=centernum;
m_pattern[i].category=centernum;
}
}
}
delete []dis;
delete []result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -