#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); }