Monday 29 June 2015

C program to construct tree using Id3 algorithm.

GitHub : https://github.com/ShivamSaluja/ML-ID3

 

Link to golf database.

Steps to run the code :
1] Save the data file with name golf.data .
2] Save the below code in a C file and name it id3.c
3] Save both database and c code in the same folder.
4] Run the code and tree will be printed as output.

C Program for Id3 :

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>


struct node
{
    int data;
    char name[15];
    struct node *next;
};

struct deci_tree
{
    int data;
    int datasetCol;
    double ent;
    int pos;
    int childno;
    int ivalue;
    struct deci_tree *c[50];
}root;


struct node  *createnewnode(struct node *head,char name[15],int d)
{
    struct node *ptr=head,*temp;

    temp=(struct node *)malloc(sizeof(struct node));
    strcpy(temp->name,name);
    temp->data=d;
    temp->next=NULL;
    if(head==NULL)
        head=temp;

    else
    {
        while(ptr->next!=NULL)
        {
            ptr=ptr->next;
        }
        ptr->next=temp;
    }

    return head;
}


int search(struct node *head,char name[15])
{
    struct node *temp=head;
    while(temp!=NULL)
    {
        if(strcmp(temp->name,name)==0)
            return temp->data;
        else
            temp=temp->next;
    }

    if(temp==NULL)
        return 3;
    else
return 0;
}


void display(struct node *head)// function to display the mapping of name and integer
{
    struct node *temp=head;

    if(temp==NULL)
        return;
    while(temp!=NULL)
    {
        printf("%d->%s\n",temp->data,temp->name);
        temp=temp->next;
    }
}


double entropy(int a[500][500],int obj,int attr,int attrpos,int val,struct deci_tree *head1)
{
    int x,k;
    x = a[1][attr-1];
    struct deci_tree *temp;
    temp = head1;
    int i;
    double b,c,d,total= 1.0;
    double count1 = 0,count2 = 0 ;

    if(temp == NULL && attrpos == attr-1)
    {
        for(i=1;i<obj;i++)
        {
            if(a[i][attrpos]==x)
                count1++;
            else
                count2++;
        }
    }

    if(temp==NULL  && attrpos != attr-1)
    {

        for(i=1; i<obj; i++)
        {
            if(a[i][attrpos] == val)
            {
                if(a[i][attr-1] == x)    
                    count1 = count1 + 1;

                else
                    count2 = count2 + 1;
            }
        }
    }
    b = count1/(count1+count2);
    c = count2/(count1+count2);


    if(count1 == 0.000000 || count2 == 0.000000)
        d = 0 ;
    else
        d =  ((count1+count2)/(obj-1)) *(-(b*(log(b)/log(2)) + c*(log(c)/log(2))));

    return d;
}

void findk(int a[500][500], int b[50][50],int obj,int attr){

    int i,j,k,count = 1;
    int flag  =0 ;

 
    for(k = 0; k < attr;k++)
    {
        b[k][1] = a[1][k];
        i = 1;
        while(i < obj){
            for(j = 1 ; j < count; j++){
                if(a[i][k] == b[k][j])
                {
                    flag = 1;  
                }
            }
            if(flag  == 0 ){
                b[k][count] = a[i][k];
                count++;
            }
            flag =0;
            i++;

        }
        b[k][0] = count-1;

        count = 1;
    }
}  


int findmax(double *gain1 , int attr){

    int i = 0 ;
    int max1 = 0 ;
    double max;
    max = gain1[0];
    for(i = 1; i <= attr; i++ ){
        if(gain1[i] > max){
            max1 = i;
            max = gain1[i];
        }
    }
    return max1;
}


double findsum(double col1[50],int len){

    int i,j;
    double sum =0;  
    for(i = 0;i < len ;i ++){
        sum =sum +col1[i];
    }      
    return sum;
}


int* funcModiA(int a[500][500],int modifiedA[500][500],int max1,int attr,int obj,int val,int dim[2]){

    int i,j,k;  
    int row = 0,col =0,temp=0,col2=0;
 
    for(j = 0 ; j < obj ; j++){
        if(j == 0 ){
            for(k =0 ; k < attr ; ){
                if(k == max1 ){
                    k++;
                }
                else{
                    modifiedA[row][col2] = a[j][k];
                    k++;
                    col2++;
                }  
            }
            row++;
        }
        else{
            if(a[j][max1] == val){
                for(i = 0 ; i < attr ;){
                    if(i == max1){
                        i++;
                    }  
                    else {              
                        modifiedA[row][col] = a[j][i];
                        temp = col++;
                        i++;
                    }
                }  
                col = 0;      
                row++;
            }
        }      
    }
    dim[0] = row;
    dim[1] = attr-1;  
    return dim;
}

struct deci_tree* infoGainRecursive(int Z[500][500],int b[50][50],struct deci_tree * parent,double entr,int max1,int attr,int obj,int flag,int initattr,int a[500][500]){

    int i =0 ;
    int j;
    int modifiedA[500][500],modifiedB[50][50];
    double col3[50],col1[50],entr1[50],entropy1[50][50],gain1[50];
    int dim[2];
    if(flag == 1){
        flag = 0;
        parent->ent = entr;
        parent->data = 0;
        for(i = 0 ; i  < attr ;i++){
            for(j = 0 ; j <  obj;j++){
                modifiedA[j][i] = Z[j][i];
            }
        }          
        findk(modifiedA,modifiedB,obj,attr);

 
    }
 
    else{

          for(i = 0 ; i  < attr ;i++){

            for(j = 0 ; j <  obj;j++){
                modifiedA[j][i] = Z[j][i];

            }
        }

        funcModiA(modifiedA,modifiedA,max1,attr,obj,parent->pos,dim);
        obj = dim[0];
        attr = dim[1];
        parent->ent = entropy(modifiedA,obj,attr,i,modifiedB[i][j],NULL);
        if(parent->ent == 0 ){
             int sd =  parent->data ;
             parent->data = modifiedA[1][attr-1];
             parent->datasetCol = attr-1;
             parent->childno = 0;      
             printf("\n\tnode %d is terminated with row value %d ,  child of %d i posotion value %d\n",parent->data , parent->pos ,sd,parent->ivalue);
             return 0;
        }
        else{
            findk(modifiedA,modifiedB,obj,attr);      
        }  
    }

    for(i= 0; i < attr-1 ; i++){
        for(j= 1 ; j <= modifiedB[i][0]; j++){  
            col3[j-1] = entropy(modifiedA,obj,attr,i,modifiedB[i][j],NULL);
     
        }
        entr1[i] =  findsum(col3,modifiedB[i][0]);
        gain1[i] =  parent->ent  - entr1[i];
    }

    int temp = max1;
    max1 = findmax(gain1,attr-1);
    parent->data = modifiedA[0][max1];
    parent->childno = modifiedB[max1][0];

    for(i = 0; i <= initattr;i++){
        if(parent->data    == a[0][i]){
            parent->datasetCol = i;
            break;
        }  
    }

    printf("\n\tCurrent node is %d and is child of %d , through  row value %d,i position %d coloum number %d \n", parent->data,Z[0][temp],parent->pos,parent->ivalue,parent->datasetCol);
 
    for(i = 1; i <= modifiedB[max1][0] ;i++) {
        parent->c[i] = (struct deci_tree *)malloc(sizeof(struct deci_tree ));  
        parent->c[i]->pos = modifiedB[max1][i];        
        parent->c[i]->data = modifiedA[0][max1];
        parent->c[i]->ent = parent->ent;
        parent->c[i]->ivalue = i;
        infoGainRecursive(modifiedA,modifiedB,parent->c[i],parent->c[i]->ent,max1,attr,obj,flag,initattr,a);
    }

    return parent;
}

int* get_test_value(int a[500][500],int attr,int obj){
 
    int i,j,flag = 0,*class,temp,counter=1;
    temp = a[1][attr-1];
    class = (int *)malloc(obj*sizeof(int));

    class[1] = temp;

    for(i = 2; i <= obj; i++ ){
        for(j = 1; j <= counter ; j++){
               if(a[i][attr-1] == class[j] ){
                    flag = 1;
                    break;
               }
        }
        if(flag == 0){
            counter++;
            class[counter] = a[i][attr-1];              
        }
        flag = 0;
    }

    class[0]=counter;
        printf("\n");
    return class;
}

int classification(int a[500][500],struct deci_tree *head,int test_data_pos,int *test_value){

    int temp,store,flag=0,class,i;
     
    struct deci_tree *ptr;
    ptr = head;
                                 
    while(flag != 1){  
        temp = a[test_data_pos][ptr->datasetCol];
        for(i =1 ; i <= ptr->childno;i++ ){
                if(ptr->c[i]->pos == temp){
                    ptr = ptr->c[i];

              }  
            }
             for(i = 1; i <= test_value[0] ; i++){
                 if(test_value[i] == ptr->data){
                    class = test_value[i];
                    flag = 1;
                 }                        
                }
    }
    return class;
}


int main(){

    struct node *first = NULL;
    struct deci_tree *head = NULL,*parent = NULL,*temphead = NULL;

    int i,j,k,t;      
    int a[500][500],obj,attr,x,*d,training,test, *test_value,class;
     
    double r,database,error=0,accuracy=0,total;

    FILE *fp;

    char *tok;  
    const char s[2]=",";

    char buff[200];

    fp=fopen("golf.data","r");

    k=4;i=0;

    while(fgets(buff,200,fp)!=NULL)
    {
        j=0;
        tok=strtok(buff,s);
        while(tok != NULL)
        {
            t=search(first,tok);
            if(t!=3)
            {
                a[i][j]=t;
                j++;
            }    
            if(t==3)// this value is understood if it is checked in search method
            {
                first= createnewnode(first,tok,k);
                a[i][j]=k;
                j++;
                k++;
            }
            tok=strtok(NULL,s);
        }

        i++;
        attr=j;
    }
    obj=i;
    display(first);

    fclose(fp);

    d = (int *)malloc(attr * sizeof(int));
    for(k = 0 ; k < attr ; k++){
        d[k] = k;
    }
    for(i=0;i<obj;i++)
    {
        printf("\n");
        for(j=0;j<attr;j++)
        {
            printf("%d\t", a[i][j]);
        }
    }

        training =obj*75/100;
        test=training;
    printf("\nTraining Data\n");
    for(i=0;i<training;i++)
    {
        printf("\n");
        for(j=0;j<attr;j++)
        {
            printf("%d\t", a[i][j]);
        }
    }
        printf("\nTest Data");
    for(i=test;i<obj;i++){
        printf("\n");
        for(j=0;j<attr;j++){
                printf("%d\t",a[i][j]);
        }
    }  


    database =  entropy(a , training,attr, attr-1,0,NULL);
    int flag = 1;
     
    parent =(struct deci_tree *)malloc(sizeof(struct deci_tree));

    head = infoGainRecursive(a,NULL,parent,database,attr,attr,training,flag,attr,a);
    return 0;
}

Sunday 28 June 2015

Golf Database used for ID3

outlook,temperature,humidity,wind,e_tennis
sunny, 85, 85, false, Don't Play
sunny, 80, 90, true, Don't Play
overcast, 83, 78, false, Play
rain, 70, 96, false, Play
rain, 68, 80, false, Play
rain, 65, 70, true, Don't Play
overcast, 64, 65, true, Play
sunny, 72, 95, false, Don't Play
sunny, 69, 70, false, Play
rain, 75, 80, false, Play
sunny, 75, 70, true, Play
overcast, 72, 90, true, Play
overcast, 81, 75, false, Play
rain, 71, 80, true, Don't Play