ID3算法具体实现

#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<vector>
#include<cmath>
using namespace std;

int n=5,cc;

struct node{
	vector<string> attribute_name;                     //当前所有数据,可用的属性名字 
	vector<vector<string> > attribute_values;         //每一行,每个属性的值 
	vector<map<string,int> > attribute_values_number;         //每个属性 : 每种值->个数 
	vector<double> attribute_entropy;                 //每个属性 : 条件熵 
	string decided_attribute;                     //  该节点的决定属性, 
	string decided_value;                      //该节点的父节点 下来的分支的值
	map<string,string> mp; 
	vector<node* > v;                        //该节点有若干子节点 
	double I_entropy;                          //信息熵 
	int flag;
	string ans;
};
void init(struct node *s);                  //初始化根节点 
void createtree(struct node *s);              //创建树 
double compute_I_entropy(struct node *s);           //计算信息熵 
void  compute_attribute_valuecount(struct node *s);    //计算每个属性的map 
void compute_attribute_entropy(struct node *s);      //计算每个属性的信息增益 
double compute_single_attribute_entropy(int index,struct node *s);           //计算单个属性的信息增益 
struct node * create_child_node(string attribute,string attribute_value,struct node *s);   //生成一个子节点 。参数为:判定属性名,属性值,去除那一列,有这个值的那一行保留 
void search(struct node *s,int t);
void search1(struct node *s);       //输出该节点的矩阵信息 

int main(void)
{
	struct node *s=new node;
	init(s);	               //输入训练数据集 	
	createtree(s);
	search(s,1);
	
	return 0;
}
void init(struct node *s)      //没问题了 
{
	int i,j;
	string str;
	vector<string> vv;
	for(i=0;i<n;i++){
		cin>>str;
		s->attribute_name.push_back(str);
	}	
	for(i=0;i<14;i++){
		vv.clear();
		for(j=0;j<5;j++){
			cin>>str;
			vv.push_back(str);
		}
		s->attribute_values.push_back(vv);
	}
	s->decided_value="根节点";
	s->flag=1;
}
void createtree(struct node *s)             // 
{
	int i,j,index=0,n,flag=0;
	double max=0;
	string flag_attribute;
	n=s->attribute_name.size()-1; 
	//判断该节点是否为叶子节点 
//	cout<<"其余属性个数:"<<n<<endl;
	if(n==0){                 //只有类别属性时,当成叶子节点,结束递归
		map<string,int> mp=s->attribute_values_number[n];
		map<string,int>::iterator ite=mp.begin();
		int mmax=0;
		string str;
		for(ite;ite!=mp.end();ite++){
			if(ite->second>max){
				str=ite->first;
			}
		}
		s->ans=str;  
		s->flag=2;        
//		cout<<"是叶子节点,不用计算其他信息从而扩展结点了"<<endl;                  
		return ;
	}
	flag_attribute=s->attribute_values[0][n];
	for(i=1;i<s->attribute_values.size();i++){
		if(s->attribute_values[i][n]!=flag_attribute){
			flag=1;
			break;
		}
	}
	if(flag==0){                             //类别属性都一样,当成叶子节点 ,结束递归 
		s->ans=flag_attribute;
		s->flag=2;
//		cout<<"是叶子节点,不用计算其他信息从而扩展结点了"<<endl; 
		return ;
	}
//	cout<<"是内部节点,需要计算其他信息,扩展结点"<<endl; 
	//是非叶子节点 
	//计算必要信息	
	compute_attribute_valuecount(s);            //计算每一列属性的键值对映射关系   1.得到vector<map<string,int> > attribute_values_number; 
	s->I_entropy=compute_I_entropy(s);          //计算信息熵                   2. 得到double I_entropy;  
	compute_attribute_entropy(s);               //计算非类别属性的信息增益    3.得到vector<double> attribute_entropy;  
	//找出非类别属性中,有最大信息增益的那个属性,作为决定属性 
	for(i=0;i<n;i++){
		if(s->attribute_entropy[i]>max){
			max=s->attribute_entropy[i];
			index=i;
		}
	}	
	s->decided_attribute=s->attribute_name[index];            //4.得到 string decided_attribute;
	map<string,int> m=s->attribute_values_number[index];
	map<string,int>::iterator ite=m.begin();
	//进行分支,得到的子节点应该包含的信息:6. 属性列表 7.属性值矩阵 8.分支值 9.特殊结点标志 
	for(ite;ite!=m.end();ite++){                       //对每个分支建树 
		struct node *ss=new node;
//		cout<<"以属性:"<<s->decided_attribute<<" 的某个值:"<<ite->first<<" 划分出一个子节点"<<endl;
//		cout<<"请输入任意数字,生成子节点";
//		cin>>cc;
		ss=create_child_node(s->decided_attribute,ite->first,s);
//		search1(ss);
		createtree(ss); 
		s->v.push_back(ss);                                      //5. 得到 子节点    vector<node* > v;
	}
}
struct node * create_child_node(string attribute,string attribute_value,struct node *s)   // 没问题了 
{
//	cout<<"开始生成子节点!"<<endl;
	struct node * st=new node;
	int i,j,k,n,row,col;
	vector<string> v; 
	string str;
	row=s->attribute_values.size();
	col=s->attribute_name.size();
	for(i=0;i<col;i++){                                    //赋 剩余属性名  得到vector<string> attribute_name;     
		if(s->attribute_name[i]!=attribute){    
			str=s->attribute_name[i];
			st->attribute_name.push_back(str);
		}
	} 
//	cout<<"属性个数:"<<st->attribute_name.size()<<endl;
//	for(i=0;i<st->attribute_name.size();i++){
//		cout<<st->attribute_name[i]<<' ';
//	} 
	cout<<endl;
	//建立二维属性值矩阵   得到 vector<vector<string> > attribute_values;
	for(i=0;i<row;i++){
		v.clear(); 
		for(j=0;j<col;j++){
			if(s->attribute_name[j]==attribute){
				if(s->attribute_values[i][j]!=attribute_value){     //去掉一行 
					break;
				}
			}
			else{                                //加入除去父节点的判定属性后剩余几个属性列的值 
				str=s->attribute_values[i][j];
				v.push_back(str);
			}
		}
		if(j>=col){
			st->attribute_values.push_back(v);    //加入一行 
		}
		else{
			//去掉一行 
		} 
	} 
	st->decided_value=attribute_value;            //该节点的父节点下来的分支值  得到string decided_value;  
	st->flag=0;                        // 标记该子节点为  非叶子节点   得到   int flag;
	st->mp[attribute]=attribute_value;
	return st; 
}
void compute_attribute_valuecount(struct node *s)   //没问题了 
{
	int i,j,k,n=s->attribute_name.size();
	map<string,int> mp;
	for(i=0;i<n;i++){                 //遍历每一个属性 ,也就是每一列 
		mp.clear();
		for(j=0;j<s->attribute_values.size();j++){             //遍历每一行 
			mp[s->attribute_values[j][i]]++;     //下面五行的简化版本 
//			for(k=0;k<n;k++){                   //遍历每一列 
//				if(s->attribute_values[j][k]==s->attribute_name[i]){ 
//					mp[s->attribute_name[i]]++;
//				}
//			}
		}
//		cout<<"属性:"<<s->attribute_name[i]<<"的值->数量 映射关系:"<<endl;
//		map<string,int>::iterator ite=mp.begin();
//		for(ite;ite!=mp.end();ite++){
//			cout<<ite->first<<':'<<ite->second<<endl;
//		}
		s->attribute_values_number.push_back(mp);
	}
}
double compute_I_entropy(struct node *s)    //没问题了 
{
	int i,j,sum,sum1,sum2,index;
	double p1,p2,ans;
	sum=s->attribute_values.size();                       //总行数 
	index=s->attribute_name.size()-1;                      //类属性 对应的索引 
//	cout<<"类属性 对应的索引:"<<index<<endl;
	map<string,int> m=s->attribute_values_number[index];   //类属性那一列  值->数量 映射关系 
	map<string,int>::iterator ite=m.begin();
	for(ite;ite!=m.end();ite++){
		if(ite->first=="是")
			sum1=ite->second;                                       //是 的数量 
		else
			sum2=ite->second;                                      //否 的数量 
	}
//	cout<<"sum1:"<<sum1<<"   sum2:"<<sum2<<"   sum:"<<sum<<endl; 
	//计算公式 
	p1=1.0*sum1/sum;                
	p2=1.0*sum2/sum;
	ans=(p1*(log(p1)/log(2)))+(p2*(log(p2)/log(2)));
	ans=fabs(ans); 
//	cout<<"信息熵:"<<ans<<endl; 
	return ans;
} 
void compute_attribute_entropy(struct node *s)   //没问题了 
{
	int i,j,k,n=s->attribute_name.size();
	double ans;
	for(i=0;i<n-1;i++){                             //计算每一个非类别属性的熵值 
		ans=compute_single_attribute_entropy(i,s);
		s->attribute_entropy.push_back(ans);
	}
}
double compute_single_attribute_entropy(int index,struct node *s)    //没问题了 
{ 
///	cout<<"对属性:"<<s->attribute_name[index]<<":"<<endl; 
	map<string,int> m;
	double ans=0.0,p1,p2;
	string str;
	int i,j,n,sum1,sum2,last;
	n=s->attribute_values.size();           //行数 
	m=s->attribute_values_number[index];            //找到那一列的map 
	last=s->attribute_name.size()-1;             //类别属性的索引 
	map<string,int>::iterator ite=m.begin();
	for(ite;ite!=m.end();ite++){                   //对每一种值 
		str=ite->first;
		sum1=sum2=0;
		for(i=0;i<n;i++){
			if(s->attribute_values[i][index]==str){          //先找到对应属性值 
				if(s->attribute_values[i][last]=="是")       // 再看它属于哪一个类别 
					sum1++;
				else
					sum2++; 
			}
		}
//		cout<<"    对值为:"<<ite->first<<" 的几行中,类别为是的有:"<<sum1<<" 个,类别为否的有:"<<sum2<<" 个。总共有"<<ite->second<<" 个"<<endl;
		p1=1.0*sum1/ite->second;
		p2=1.0*sum2/ite->second;
		if(p1==0)
			p1=1;
		if(p2==0)
			p2=1;
//		cout<<"    p1:"<<p1<<"   p2:"<<p2<<endl; 
		ans+=(-1.0)*(ite->second)/n*(p1*(log(p1)/log(2))+p2*(log(p2)/log(2)));
	}
	cout<<"信息熵:"<<s->I_entropy<<endl;
	cout<<"条件熵:"<<ans<<endl;
	ans=s->I_entropy-ans;               //返回每个属性的信息增益 
	cout<<"信息增益:"<<ans<<endl; 
	return ans;
}
void search(struct node *s,int t)
{
	int i,j,n=s->attribute_name.size();
//	cout<<s->decided_value<<' '<<endl;
	if(s->flag==1){
//		cout<<s->decided_attribute<<':';
	} 
	else if(s->flag==2){                   
//		cout<<" 叶子节点: "; 
		cout<<s->decided_value<<' ';
		cout<<" 类别:"<<s->ans<<endl; 
		return ;
	}
	else{
//		cout<<" 非叶子节点 ";
		cout<<s->decided_value<<' '; 
	}
	for(i=0;i<s->v.size();i++){
		for(j=1;j<=t;j++)
			cout<<"   "; 
//		if(s->flag==1)
//			cout<<"路径"<<cnt<<':';
		cout<<s->decided_attribute<<":";
		search(s->v[i],i+1);
	}
}
void search1(struct node *s)      //输出矩阵信息 
{
	int i,j,n=s->attribute_name.size();
	int row,col;
	row=s->attribute_values.size();
	col=s->attribute_name.size();
	for(i=0;i<n;i++){
		cout<<s->attribute_name[i]<<' ';
	}
	cout<<endl;
	for(i=0;i<row;i++){
		for(j=0;j<col;j++){
			cout<<s->attribute_values[i][j]<<' ';
		}
		cout<<endl;
	}
	cout<<"决定属性值:"<<s->decided_value<<endl;
	cout<<"节点类型:"<<s->flag<<endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值