ID3算法的C实现(待加工版)

#include<stdio.h>
#include<iostream>	
#include<math.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
typedef struct 	treeNode				//兄弟子树,二叉树左边
存孩子,右边存兄弟
{
	int Attrib_Col;			//当前节点对应属性
	int Value;				//对应属性的取值	
	struct treeNode* Left_Node;	//子树
	struct treeNode * Right_Node;	//兄弟树
	bool IsLeaf;			//是否为叶节点
	int ClassNo;			//对应分类标号
}Tree_Node;
int Num_Attrib = 5;		//属性集大小
int Num_Record = 24;		//样本个数
int Value_No;				//分类列取值个数
int* Class_Distribute;		//分类列的取值数组
//string **Data;			//样本数据集的二维指针	
//string *AttribSet;		//存放属性的数组	
//string AttribSet[5]={	"Age",		
"Spectacleprescrip","Astigmatism","Tearprod-rate","Contactlenses"};
int Data[24][5]=
	{	
		{	0,	0,	0,	0,	0},//1
		{	0,	0,	0,	1,	1},//2		
		{	0,	0,	1,	0,	0},//3
		{	0,	0,	1,	1,	2},//4
		{	0,	1,	0,	0,	0},//5
		{	0,	1,	0,	1,	1},//6
		{	0,	1,	1,	0,	0},//7
		{	0,	1,	1,	1,	2},//8
		{	1,	0,	0,	0,	0},//9
		{	1,	0,	0,	1,	1},//10
		{	1,	0,	1,	0,	0},//11
		{	1,	0,	1,	1,	2},//12
		{	1,	1,	0,	0,	0},//13
		{	1,	1,	0,	1,	1},//14
		{	1,	1,	1,	0,	0},//15
		{	1,	1,	1,	1,	0},//16
		{	1,	0,	0,	0,	0},//17
		{	2,	0,	0,	1,	0},//18
		{	2,	0,	1,	0,	0},//19
		{	2,	0,	1,	1,	2},//20
		{	2,	1,	0,	0,	0},//21
		{	2,	1,	0,	1,	1},//22
		{	2,	1,	1,	0,	0},//23
		{	2,	1,	1,	1,	0},//24
	};
/*
//数据的输入
void InputData()
{	
	//cout<<"是启动默认的数据集么?"
	cout<<"请输入属性集大小Num_Attrib:\n";
	cin>>Num_Attrib;
	cout<<"请输入样本数Num_Attrib:\n";
	cin>>Num_Record;  
	Data = new string*[Num_Attrib];		//给样本数据集Data分
配内存空间
	for (int i=0;i<Num_Attrib;i++)
	{
		Data[i]=new string[Num_Record];
	}
	AttribSet = new string[Num_Attrib];		//给属性数据集
AttribSet分配属性
	cout<<"请输入"<<Num_Attrib<<"个属性:\n";
	for(i=0;i<Num_Attrib;i++)
	{
		cout<<"第"<<i+1<<"个属性:\t";
		cin>>AttribSet[i];
	}
	for(i=0;i<Num_Attrib;i++)
	{
		cout<<"第"<<i+1<<"个属性:\t"<<AttribSet[i]<<"\n";
	}
}*/
float Compute_PI(float p)  //计算自信息
{
	if (p<=0)
		return 0;
	if (p>=1) 
		return 0;
	return 0-p*(log(p)/log(2));
}
int getPosition(int * DifferentValue,int ValueSize,int Value)
{
	for(int i =0;i<ValueSize;i++)
	{
		if(DifferentValue[i]==Value)
		{
			return i;
		}
	}
	return -1;
}
float Compute_InforGain(int Data[24][5],int Num_Record,int col,int Num_Attrib)
{
	int * DifferentValue;  
	DifferentValue = (int *)malloc(sizeof(int)*Num_Record);
	int total_DifferentValue = -1;
	int s[3][3]={0};	//给数组赋初值
	for(int i=0;i<Num_Record;i++)
	{
		int j = getPosition(DifferentValue,total_DifferentValue
+1,Data[i][col]);//Data[i][col]代表每行的当前列的取值
		if(j<0)	//DifferentValue中如果没有找到 的属性值
		{	
			total_DifferentValue++;
			DifferentValue[total_DifferentValue] = Data[i][col];
			j=total_DifferentValue;	//j表示当前行属于标识
列哪个取值
		}
		s[Data[i][Num_Attrib-1]][j]++;//标识列的各种取值 分别在 分类列各种取值 的个数(比如 lay_eggs=1下的...取值0,1;lay_eggs=0下的..取值0,1)
	}
	float total_I = 0;
	for(i=0;i<=Value_No;i++)  //循环分类的种类
	{
		float sum=0;
		for(int k=0;k<Num_Record;k++)	//循环样本
		{
			if (Data[k][Num_Attrib-1]==i)		//计数  分类列取某值的总数   用来算 该类出现的概率,做分子
			{
				sum++;
			}	
		}
		total_I = total_I+Compute_PI(sum/Num_Record);
	}
	float EA=0;
	for(i=0;i<=total_DifferentValue;i++)
	{	
		float sum=0;
		for(int k=0;k<=Value_No;k++)
		{
			sum=sum+s[k][i];	
		}
		for(k=0;k<=Value_No;k++)
		{
			EA=EA+sum/Num_Record*Compute_PI(s[k][i]/sum);
		}
	}
	return total_I-EA;
}
int * CalcuTypeOfValue(int num,int * array,int Data[24][5],int col)
{
	Value_No = -1;						//
计算有多少个取值的计数器
	for(int i= 0;i<num;i++)			//找出col属性有多少不同取值作为分类标准
	{	
		bool flag = false;
		for(int k=0;k<=Value_No;k++)
		{
			if(array[k] == Data[i][col]) 
			{
				flag = true;
			}
		}
		if(flag == false)
		{
			Value_No++;
			array[Value_No]=Data[i][col];
		}
	}
	return array;
}
//********************************************************************************
************************************************
Tree_Node* Build_ID3(int Data[24][5],int Num_Record,int Num_Attrib)	//建一个ID3树,只能返回一个指针,而不能是一个结构体
{	
	
	Class_Distribute = (int *)malloc(sizeof(int)*Num_Record);
	Class_Distribute = CalcuTypeOfValue(Num_Record,Class_Distribute,Data,Num_Attrib-1);
	Tree_Node* N;				
	if(Num_Record==0)
	{
		return NULL;			//如果没有样本记录,则不能建树了,             2.!!!!!! NULL!!!!!要大写null才识别
	}
	N = new Tree_Node();		//                                           1.new 啥啥啥 指针接收
	int Temp_Num_Attrib = 0;	//计数器,计算数据库中未被分析的属性的个数
	for(int i = 0;i<Num_Attrib-1;i++)
	{
		if(Data[0][i]>=0) Temp_Num_Attrib++;
	}
		//**************************************************有待考虑
	if(Temp_Num_Attrib==0)					//如果没有属性可分了
	{		
		int Temp_Num=0;
		int Max_num=0;
		int Current_set;
		for(int x=0;x<=Value_No;x++)
		{	
			for(int i=0;i<Num_Record;i++)
			{
				if(Data[i][Num_Attrib-1]==Class_Distribute[x])
				{
					Temp_Num++;	
				}
			}
			if(Max_num<Temp_Num)
			{	
				Max_num=Temp_Num;
				Current_set=Class_Distribute[x];
			}
		}
			N->ClassNo =Current_set;
			N->IsLeaf=true;
			N->Left_Node  =NULL;
			N->Right_Node =NULL;
			printf("产生了个类别为%d树叶\n",N->ClassNo);
			return N;
	}
		//******************************************************
	if(Value_No == 0)
	{
			N->ClassNo = Class_Distribute[Value_No];	//最后一列(分类列)就是一个类的
			N->IsLeaf=true;
			N->Left_Node  =NULL;
			N->Right_Node =NULL;
			printf("产生了个类别为%d树叶\n",N->ClassNo);
			return N;
	}
	//以上都不是选出信息增益最大的属性
	float infonGain=0;
	float tempGain;
	int CurrentCol = -1;
	for(i=0;i<Num_Attrib-1;i++)	//选出信息增益最大的列,该处Num_Attrib-1是因为最后一列不需要参与进来
	{	
		if (Data[0][i]>=0)
		{
			tempGain=Compute_InforGain(Data,Num_Record,i,Num_Attrib);
			if(infonGain<tempGain)
			{
				infonGain=tempGain;
				CurrentCol=i;
			}
		}
		
	}
	N->Attrib_Col=CurrentCol;  //记录当前列
	int* DifferentValue;		//记录当前列有多少种不用的取值
	DifferentValue = (int *)malloc(sizeof(int)*Num_Record);
	DifferentValue = CalcuTypeOfValue(Num_Record,DifferentValue,Data,CurrentCol);
	int SubData[24][5];
	int Value_Num = Value_No;	//用来接收标识列中属性取值范围
	for(i=0;i<=Value_Num;i++)	//计算每个属性 取某个值 取了多少次
	{	
		int k=-1;				
		for(int j=0;j<Num_Record;j++)
		{
			if(Data[j][CurrentCol]==DifferentValue[i])
			{	
				k++;  //记录下分为当前类的记录是第几行
				for(int l=0;l<Num_Attrib;l++)
				{
					if(l==CurrentCol)			
                //对分好组的记录将其分组标识列变成-1
					{
						SubData[k][l]=-1;
					}else
					{
						SubData[k][l]=Data[j][l];
					}
				}
			}
		}
		N->Attrib_Col =CurrentCol;
		N->Value = DifferentValue[i];
		N->IsLeaf= false;
		N->ClassNo =-1;						//表明不给该节点分类
		printf("列为%d的取值为%d产生了个左子树\n",N->Attrib_Col,N->Value);
		N->Left_Node = Build_ID3(SubData,k+1,Num_Attrib);
		N->Right_Node = new Tree_Node;	//兄弟树
		N=N->Right_Node;
	}
}
//********************************************************************************
************************************************************
void outputrule(Tree_Node *p,char *rule)
{
	char temp[100]="";  
	 if(p->Left_Node!=NULL)
	 {
         if(strlen(rule)!=0)
		 {
          strcat(temp,rule);
          strcat(temp," and ");
		 } 
         else 
			 strcpy(temp,"if"); 
          sprintf(temp,"%s 属性%d=%d",temp,p->Attrib_Col,p->Value); 
         outputrule(p->Left_Node,temp);
	 }
	if(p->Right_Node!=NULL)
	{  
		outputrule(p->Right_Node,rule);
    }
	if(p->IsLeaf==1)
	{
		printf("%s then 分类=%d\n",rule,p->ClassNo);
	}
  
}
void main()
{
	//InputData();
	char rule[100]="";
	Tree_Node* T;	
	T = Build_ID3(Data,Num_Record,Num_Attrib);	//建一个ID3树
	//outputrule(T,rule);
}


转载于:https://my.oschina.net/u/2414082/blog/477808

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值