#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;
}
ID3算法具体实现
最新推荐文章于 2024-04-18 23:28:44 发布