📄 myisodata.cpp
字号:
// myisodata.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "math.h"
#include "fstream"
#include <iostream>
using namespace std;
#define N 150 //总的样本个数
#define NA 4 //属性个数
#define eps 0.00001
struct PointF //读入样本的结构体,每个样本有一个序号,和四个属性值
{
int label;
float x1;
float x2;
float x3;
float x4;
};
struct PointZ //每个聚类中心的结构体
{
float x1;
float x2;
float x3;
float x4;
};
float CalDistanceF(PointF X1,PointF X2)
{
return (float)sqrt((X1.x1-X2.x1)*(X1.x1-X2.x1)+(X1.x2-X2.x2)*(X1.x2-X2.x2)+(X1.x3-X2.x3)*(X1.x3-X2.x3)+(X1.x4-X2.x4)*(X1.x4-X2.x4));
}
float CalDistanceZ(PointZ X1,PointZ X2)
{
return (float)sqrt((X1.x1-X2.x1)*(X1.x1-X2.x1)+(X1.x2-X2.x2)*(X1.x2-X2.x2)+(X1.x3-X2.x3)*(X1.x3-X2.x3)+(X1.x4-X2.x4)*(X1.x4-X2.x4));
}
float CalDistanceFZ(PointF X1,PointZ X2)
{
return (float)sqrt((X1.x1-X2.x1)*(X1.x1-X2.x1)+(X1.x2-X2.x2)*(X1.x2-X2.x2)+(X1.x3-X2.x3)*(X1.x3-X2.x3)+(X1.x4-X2.x4)*(X1.x4-X2.x4));
}
int _tmain(int argc, _TCHAR* argv[])
{
//--------------------------------------------------------------------------------------------------
//读取样本
PointF pts[N];
ifstream infile("iris.txt");
if(!infile)
{
cout<<"can't open the file"<<endl;
exit(1);
}
int i=0;
int j=0;
while(!infile.eof()) //从文件中读取样本
{
infile>>pts[i].label;
infile>>pts[i].x1;
infile>>pts[i].x2;
infile>>pts[i].x3;
infile>>pts[i].x4;
i++;
}
cout<<"样本集合为:"<<endl;
for(i=0;i<N;i++)
{
printf("X%d:(%.1f,%.1f,%.1f,%.1f) ",pts[i].label,pts[i].x1,pts[i].x2,pts[i].x3,pts[i].x4);
if((i+1)%3==0)
printf("\n");
}
cout<<endl;
cout<<endl;
//---------------------------------------------------------------------------------------------------
int Nc=1; //初始聚类类别数为1
PointZ ZArray[N]; //存放聚类中心的一个数组
for(i=0;i<N;i++) //初始化聚类中心为全0
{
ZArray[i].x1=0;
ZArray[i].x2=0;
ZArray[i].x3=0;
ZArray[i].x4=0;
}
ZArray[0].x1=pts[0].x1; //初始化聚类中心为第一个样本
ZArray[0].x2=pts[0].x2;
ZArray[0].x3=pts[0].x3;
ZArray[0].x4=pts[0].x4;
PointF SAArray[N][N]; //存放属于每个类别的样本
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
SAArray[i][j].label=0;
SAArray[i][j].x1=0;
SAArray[i][j].x2=0;
SAArray[i][j].x3=0;
SAArray[i][j].x4=0;
}
}
int Nj[N]; //存放每类中样本的个数
for(i=0;i<N;i++) //初始化每类样本个数为0
Nj[i]=0;
int K,ThetaN; //目标聚类类别数,每个类别最少的样本个数
float ThetaS,ThetaC;
int I=1; //最大迭代次数
int J=1; //初始迭代次数
//------------------------------------------------------------------
//分裂时用到的变量
float DAv=0; //存放总平均距离
int Nreal=N;
int m=0;
float temp=0.0;
float DjAv[N]; //存放每类内部样本和中心点的平均距离
float Deltaj[N][4]; //记录每个类别标准偏差
float Deltajmax[N]; //记录每个类别标准偏差的最大分量
int DeltajmaxCor[N]; //记录每个类别标准偏差的最大分量的那个下标
//------------------------------------------------------------------
//合并时用到的变量
float Dij[N*N/2]; //记录的是类间距离
int Diji[N]; //记录的是类间距离的一个类别号
int Dijj[N]; //记录的是类间距离的另一个类别号
float ft=0; //以下三个变量存放临时值
int it=0;
int jt=0;
int ss=0; //记录的是两两类别组合的个数
Step1:
printf("输入预期聚类中心数目 K :");
scanf("%d",&K);
printf("输入每个聚类域中最少的样本数ThetaN: ");
scanf("%d",&ThetaN);
printf("输入同一聚类域中样本标准差的最大值ThetaS: ");
scanf("%f",&ThetaS);
printf("输入不同聚类域距离最小值ThetaC: ");
scanf("%f",&ThetaC);
printf("输入最大迭代次数I: ");
scanf("%d",&I);
Step2:
for(i=0;i<Nc;i++)
{
Nj[i]=0;
}
for(i=0;i<Nc;i++)
{
for(j=0;j<N;j++)
{
SAArray[i][j].label=0;
SAArray[i][j].x1=0;
SAArray[i][j].x2=0;
SAArray[i][j].x3=0;
SAArray[i][j].x4=0;
}
}
printf("\n");
printf("这是第%d次聚类:\n",J);
for(i=0;i<N;i++) //将模式样本归类
{
if(pts[i].label==-1)
continue; //若该点的序号为-1则说明它是被剔除的
float dis=1.0e+10;
int min=0;
float ftemp;
for(j=0;j<Nc;j++) //计算每个样本到每个类别中心的距离,并找到最小的那个对应的类别号
{
ftemp=CalDistanceFZ(pts[i],ZArray[j]);
if(ftemp<dis||fabs(dis-ftemp)<eps)
{
min=j;
dis=ftemp;
}
}
SAArray[min][Nj[min]].x1=pts[i].x1; //存放归类到每个类别的样本
SAArray[min][Nj[min]].x2=pts[i].x2;
SAArray[min][Nj[min]].x3=pts[i].x3;
SAArray[min][Nj[min]].x4=pts[i].x4;
SAArray[min][Nj[min]].label=pts[i].label; //存放在每个类别的样本的序号
Nj[min]=Nj[min]+1; //该类别的样本个数自增
}
for(i=0;i<Nc;i++)
{
printf("第%d个聚类中心是:(%.2f,%.2f,%.2f,%.2f)\n ",(i+1),ZArray[i].x1,ZArray[i].x2,ZArray[i].x3,ZArray[i].x4);
printf("包含的元素有:\n");
for(j=0;j<Nj[i];j++)
{
printf(" %d ",SAArray[i][j].label); //输出每个类别的样本的序号
if((j+1)%10==0)
printf("\n");
}
printf("\n");
}
J++;
Step3:
for(j=1;j<Nc;j++) //对每类的样本数进行判断
{
if(Nj[j]<ThetaN) //如果该类的样本数小于规定的最小值,就将该聚类集合删除,包括样本
{
for(i=0;i<Nj[j];i++)
pts[SAArray[j][i].label].label=-1;
i=j;
Nreal-=Nj[j];
while(i<Nc-1) //将当前类别后面的类别信息都往前面移,去掉当前类别
{
for(m=0;m<Nj[i+1];m++)
{
SAArray[i][m].label=SAArray[i+1][m].label;
SAArray[i][m].x1=SAArray[i+1][m].x1;
SAArray[i][m].x2=SAArray[i+1][m].x2;
SAArray[i][m].x3=SAArray[i+1][m].x3;
SAArray[i][m].x4=SAArray[i+1][m].x4;
}
i++;
}
for(m=0;m<Nj[Nc-1];m++)
{
SAArray[Nc-1][m].label=0;
SAArray[Nc-1][m].x1=0;
SAArray[Nc-1][m].x2=0;
SAArray[Nc-1][m].x3=0;
SAArray[Nc-1][m].x4=0;
}
i=j;
while(i<Nc-1)
{
ZArray[i].x1=ZArray[i+1].x1;
ZArray[i].x2=ZArray[i+1].x2;
ZArray[i].x3=ZArray[i+1].x3;
ZArray[i].x4=ZArray[i+1].x4;
i++;
}
ZArray[Nc-1].x1=0;
ZArray[Nc-1].x2=0;
ZArray[Nc-1].x3=0;
ZArray[Nc-1].x4=0;
i=j;
while(i<Nc-1)
{
Nj[i]=Nj[i+1];
i++;
}
Nj[Nc-1]=0;
Nc--; //总的类别数减1
//goto Step2;
}
}
Step4: //修正各聚类中心
for(j=0;j<Nc;j++)
{
float temp1=0,temp2=0,temp3=0,temp4=0;
for(i=0;i<Nj[j];i++)
{
temp1+=SAArray[j][i].x1;
temp2+=SAArray[j][i].x2;
temp3+=SAArray[j][i].x3;
temp4+=SAArray[j][i].x4;
}
ZArray[j].x1=temp1/Nj[j];
ZArray[j].x2=temp2/Nj[j];
ZArray[j].x3=temp3/Nj[j];
ZArray[j].x4=temp4/Nj[j];
}
Step5://计算各聚类域中诸样本与聚类中心的平均距离
for(i=0;i<N;i++)
DjAv[i]=0;
for(j=0;j<Nc;j++)
{
for(i=0;i<Nj[j];i++)
{
temp+=CalDistanceFZ(SAArray[j][i],ZArray[j]);
}
DjAv[j]=temp/Nj[j];
temp=0.0;
}
//for(i=0;i<Nc;i++)
// cout<<DjAv[i]<<' ';
//cout<<endl;
Step6://计算全部模式样本对应聚类中心的总平均距离
for(j=0;j<Nc;j++)
{
DAv+=Nj[j]*DjAv[j];
}
DAv/=Nreal;
Step7:
if(J>I) goto Step14;
if(Nc<=K/2)goto Step8;
if((J%2==0)||Nc>=2*K)
goto Step11;
Step8: //计算各聚类中样本距离标准差
for(j=0;j<Nc;j++)
{
for(i=0;i<4;i++)
Deltaj[j][i]=0;
}
for(j=0;j<Nc;j++)
{
float temp1=0,temp2=0,temp3=0,temp4=0;
for(i=0;i<Nj[j];i++)
{
temp1+=(SAArray[j][i].x1-ZArray[j].x1)*(SAArray[j][i].x1-ZArray[j].x1);
temp2+=(SAArray[j][i].x2-ZArray[j].x2)*(SAArray[j][i].x2-ZArray[j].x2);
temp3+=(SAArray[j][i].x3-ZArray[j].x3)*(SAArray[j][i].x3-ZArray[j].x3);
temp4+=(SAArray[j][i].x4-ZArray[j].x4)*(SAArray[j][i].x4-ZArray[j].x4);
}
Deltaj[j][0]=(float)sqrt(temp1/Nj[j]);
Deltaj[j][1]=(float)sqrt(temp2/Nj[j]);
Deltaj[j][2]=(float)sqrt(temp3/Nj[j]);
Deltaj[j][3]=(float)sqrt(temp4/Nj[j]);
temp1=0,temp2=0,temp3=0,temp4=0;
}
/*for(j=0;j<Nc;j++)
{
cout<<Deltaj[j][0]<<' '<<Deltaj[j][1]<<' '<<Deltaj[j][2]<<' '<<Deltaj[j][3]<<endl;
}*/
Step9: //计算每类标准差的最大分量
for(i=0;i<Nc;i++)
{
Deltajmax[i]=0;
}
for(i=0;i<Nc;i++)
{
DeltajmaxCor[i]=0;
}
for(j=0;j<Nc;j++)
{
int index=0;
float max=Deltaj[j][0];
for (i=1;i<4;i++)
{
if(Deltaj[j][i]>max)
{
max=Deltaj[j][i];
index=i;
}
}
Deltajmax[j]=max;
DeltajmaxCor[j]=index;
}
/*for(j=0;j<Nc;j++)
{
cout<<Deltajmax[j]<<' '<<endl;
}*/
Step10:
for(j=0;j<Nc;j++)
{
if(Deltajmax[j]>ThetaS)
{
if((DjAv[j]>DAv&&Nj[j]>2*(ThetaN+1))||Nc<=K/2)
{
float Garma=0.5;
PointZ Zj1,Zj2;
//根据课件,使用的是第2种构造方法
if(DeltajmaxCor[j]==0)
{
Zj1.x1=ZArray[j].x1+Deltajmax[j]*Garma;
Zj1.x2=ZArray[j].x2;
Zj1.x3=ZArray[j].x3;
Zj1.x4=ZArray[j].x4;
Zj2.x1=ZArray[j].x1-Deltajmax[j]*Garma;
Zj2.x2=ZArray[j].x2;
Zj2.x3=ZArray[j].x3;
Zj2.x4=ZArray[j].x4;
}
else if(DeltajmaxCor[j]==1)
{
Zj1.x1=ZArray[j].x1;
Zj1.x2=ZArray[j].x2+Deltajmax[j]*Garma;
Zj1.x3=ZArray[j].x3;
Zj1.x4=ZArray[j].x4;
Zj2.x1=ZArray[j].x1;
Zj2.x2=ZArray[j].x2-Deltajmax[j]*Garma;
Zj2.x3=ZArray[j].x3;
Zj2.x4=ZArray[j].x4;
}
else if(DeltajmaxCor[j]==2)
{
Zj1.x1=ZArray[j].x1;
Zj1.x2=ZArray[j].x2;
Zj1.x3=ZArray[j].x3+Deltajmax[j]*Garma;
Zj1.x4=ZArray[j].x4;
Zj2.x1=ZArray[j].x1;
Zj2.x2=ZArray[j].x2;
Zj2.x3=ZArray[j].x3-Deltajmax[j]*Garma;
Zj2.x4=ZArray[j].x4;
}
else if(DeltajmaxCor[j]==3)
{
Zj1.x1=ZArray[j].x1;
Zj1.x2=ZArray[j].x2;
Zj1.x3=ZArray[j].x3;
Zj1.x4=ZArray[j].x4+Deltajmax[j]*Garma;
Zj2.x1=ZArray[j].x1;
Zj2.x2=ZArray[j].x2;
Zj2.x3=ZArray[j].x3;
Zj2.x4=ZArray[j].x4-Deltajmax[j]*Garma;
}
ZArray[j].x1=Zj1.x1;
ZArray[j].x2=Zj1.x2;
ZArray[j].x3=Zj1.x3;
ZArray[j].x4=Zj1.x4;
ZArray[Nc].x1=Zj2.x1;
ZArray[Nc].x2=Zj2.x2;
ZArray[Nc].x3=Zj2.x3;
ZArray[Nc].x4=Zj2.x4;
Nc++;
goto Step2;
}
}
}
Step11: //计算两两聚类中心之间的距离
for(i=0;i<N;i++)
{
Dij[i]=0;
Diji[i]=0;
Dijj[i]=0;
}
ss=0;
for(i=0;i<Nc-1;i++)
{
for(j=i+1;j<Nc;j++)
{
Dij[ss]=CalDistanceZ(ZArray[i],ZArray[j]);
Diji[ss]=i;
Dijj[ss]=j;
ss++;
}
}
Step12: //每次只考虑合并一对,找出类间距离最小的那对
ft=Dij[0];
it=Diji[0];
jt=Dijj[0];
for(i=1;i<ss;i++)
{
if(Dij[i]<ft)
{
ft=Dij[i];
it=Diji[i];
jt=Dijj[i];
}
}
Step13:
if(ft<ThetaC)
{
//合并后的中心存在it处
ZArray[it].x1=(Nj[it]*ZArray[it].x1+Nj[jt]*ZArray[jt].x1)/(Nj[it]+Nj[jt]);
ZArray[it].x2=(Nj[it]*ZArray[it].x2+Nj[jt]*ZArray[jt].x2)/(Nj[it]+Nj[jt]);
ZArray[it].x3=(Nj[it]*ZArray[it].x3+Nj[jt]*ZArray[jt].x3)/(Nj[it]+Nj[jt]);
ZArray[it].x4=(Nj[it]*ZArray[it].x4+Nj[jt]*ZArray[jt].x4)/(Nj[it]+Nj[jt]);
//将jt后面的中心都往前移
j=jt;
while(j<Nc-1)
{
ZArray[j].x1=ZArray[j+1].x1;
ZArray[j].x2=ZArray[j+1].x2;
ZArray[j].x3=ZArray[j+1].x3;
ZArray[j].x4=ZArray[j+1].x4;
j++;
}
ZArray[Nc-1].x1=0;
ZArray[Nc-1].x2=0;
ZArray[Nc-1].x3=0;
ZArray[Nc-1].x4=0;
j=jt;
while(j<Nc-1)
{
Nj[j]=Nj[j+1];
j++;
}
Nj[Nc-1]=0;
Nc--;
}
Step14:
if(J>I)
{
J=0;
printf("\n");
printf("共分为%d类\n",Nc);
for(i=0;i<Nc;i++) //将最后聚类信息输出
{
printf("第%d个聚类中心是:(%.2f,%.2f,%.2f,%.2f)\n ",(i+1),ZArray[i].x1,ZArray[i].x2,ZArray[i].x3,ZArray[i].x4);
printf("包含的元素有:\n");
for(j=0;j<Nj[i];j++)
{
printf(" %d ",SAArray[i][j].label); //输出每个类别的样本的序号
if((j+1)%10==0)
printf("\n");
}
printf("\n");
}
while(1);
return 0;
}
else
goto Step2;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -