⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 myisodata.cpp

📁 isodata算法
💻 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 + -