#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