zoukankan      html  css  js  c++  java
  • 机器学习算法之一(C4.5)

      在机器学习中,决策树是一个预测模型:它代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分岔路径则代表的某个可能的属性值,而每个叶节点则对应从根节点到该叶节点所经历的路径所表示的值。决策树仅有单一输出,若欲有复数输出,可以建立独立的决策树以处理不同输出。

      从数据产生决策树的机器学习技术叫做决策树学习,通俗说就是决策树。

      决策树学习也是数据挖掘中一个普通的方法。在这里,每个决策树都表述了一种树形结构,他有他的分支来对该类型的对象依靠属性进行修剪。每个决策树可以依靠对源数据库的分割进行数据测试。这个过程可以递归式的对树进行修剪。当不能再进行分割或一个单独的类可以被应用于某一分支时,递归过程就完成了。另外,随机森林分类器将许多决策树结合起来以提升分类的正确率。

      决策树同时也可以依靠计算条件概率来构造。决策树如果依靠数学的计算方法可以取得更加理想的效果。

      决策树是如何工作的?

      决策时一般都是自上而下的来生成的。

      选择分割的方法有好几种,但是目的都是一致的:对目的尝试进行最佳的分割。

      从根到叶子节点都有一条路径,这条路径就是一条“规则”。

      决策树可以是二叉的,也可以是多叉的。

      对每个节点的衡量:

    1. 通过该节点的记录数
    2. 如果是叶子节点的话,分类的路径  
    3. 对叶子节点正确分类的比例  

      有些规则的效果可以比其他的一些规则要好。

      由于ID3算法在实际应用中存在一些问题,于是Quilan提出了C4.5算法,严格来说C4.5只能是ID3的一个改进算法。ID3算法简介。

      C4.5算法继承了ID3算法的优点,并在以下几方面对ID3算法进行改进:

    • 用信息增益率来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性的不足;
    • 在数构造过程中进行剪枝;
    • 能够完成对连续属性的离散化处理;
    • 能够对不完整数据进行处理。

      C4.5算法有如下优点:产生的分类规则易于理解,准确率较高。其缺点是:在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效。此外,C4.5只适合于能够驻留于内存的数据集,当训练集大得无法再内存容纳时程序无法运行。

      1 // C4.5_test.cpp : Defines the entry point for the console application.
      2 //
      3 #include "stdafx.h"
      4 #include <stdio.h>
      5 #include <math.h>
      6 #include "malloc.h"
      7 #include <stdlib.h>
      8 const int MAX = 10;
      9 int** iInput;
     10 int i = 0;//列数
     11 int j = 0;//行数
     12 void build_tree(FILE *fp, int* iSamples, int* iAttribute,int ilevel);//输出规则
     13 int choose_attribute(int* iSamples, int* iAttribute);//通过计算信息增益率选出test_attribute
     14 double info(double dTrue,double dFalse);//计算期望信息
     15 double entropy(double dTrue, double dFalse, double dAll);//求熵
     16 double splitinfo(int* list,double dAll);
     17 int check_samples(int *iSamples);//检查samples是否都在同一个类里
     18 int check_ordinary(int *iSamples);//检查最普通的类
     19 int check_attribute_null(int *iAttribute);//检查attribute是否为空
     20 void get_attributes(int *iSamples,int *iAttributeValue,int iAttribute);
     21 int _tmain(int argc, _TCHAR* argv[])
     22 {
     23  FILE *fp;
     24  FILE *fp1;
     25  char iGet;
     26  int a = 0;
     27  int b = 0;//a,b是循环变量
     28  int* iSamples;
     29  int* iAttribute;
     30  fp = fopen("c:\\input.txt","r");
     31  if (NULL == fp)
     32  {
     33   printf("error\n");
     34   return 0;
     35  }
     36  iGet = getc(fp);
     37  
     38  while (('\n' != iGet)&&(EOF != iGet))
     39  {
     40   if (',' == iGet)
     41   {
     42    i++;
     43   }
     44   iGet = getc(fp);
     45  }
     46  i++;
     47  
     48  iAttribute = (int *)malloc(sizeof(int)*i);
     49  for (int k = 0; k<i; k++)
     50  {
     51   iAttribute[k] = (int)malloc(sizeof(int));
     52   iAttribute[k] = 1;
     53  }
     54  while (EOF != iGet)
     55  {
     56   if ('\n' == iGet)
     57   {
     58    j++;
     59   }
     60   iGet = getc(fp);
     61  }
     62  j++;
     63  
     64  iInput = (int **)malloc(sizeof(int*)*j);
     65  iSamples = (int *)malloc(sizeof(int)*j);
     66  for (a = 0;a < j;a++)
     67  {
     68   iInput[a] = (int *)malloc(sizeof(int)*i);
     69   iSamples[a] = (int)malloc(sizeof(int));
     70   iSamples[a] = a;
     71  }
     72  a = 0;
     73  fclose(fp);
     74  fp=fopen("c:\\input.txt","r");
     75  iGet = getc(fp);
     76  while(EOF != iGet)
     77  {
     78   if ((',' != iGet)&&('\n' != iGet))
     79   {
     80    iInput[a][b] = iGet - 48;
     81    b++;
     82   }
     83   if (b == i)
     84   {
     85    a++;
     86    b = 0;
     87   }
     88   iGet = getc(fp);
     89  }
     90  
     91  fp1 = fopen("d:\\output.txt","w");
     92  build_tree(fp1,iSamples,iAttribute,0);
     93  fclose(fp);
     94  return 0;
     95 }
     96 
     97 void build_tree(FILE * fp, int* iSamples, int* iAttribute,int level)//
     98 {
     99  int iTest_Attribute = 0;
    100  int iAttributeValue[MAX];
    101  int k = 0;
    102  int l = 0;
    103  int m = 0;
    104  int *iSamples1;
    105  for (k = 0; k<MAX; k++)
    106  {
    107   iAttributeValue[k] = -1;
    108  }
    109  if (0 == check_samples(iSamples))
    110  {
    111   fprintf(fp,"result: %d\n",iInput[iSamples[0]][i-1]);
    112   return;
    113  }
    114  if (1 == check_attribute_null(iAttribute))
    115  {
    116   fprintf(fp,"result: %d\n",check_ordinary(iSamples));
    117   return;
    118  }
    119  iTest_Attribute = choose_attribute(iSamples,iAttribute);
    120  iAttribute[iTest_Attribute] = -1;
    121  get_attributes(iSamples,iAttributeValue,iTest_Attribute);
    122  k = 0;
    123  while ((-1 != iAttributeValue[k])&&(k < MAX))
    124  {
    125   l = 0;
    126   m = 0;
    127   while ((-1 != iSamples[l])&&(l < j))
    128   {
    129    if (iInput[iSamples[l]][iTest_Attribute] == iAttributeValue[k])
    130    {
    131     m++;
    132    }
    133    l++;
    134   }
    135   iSamples1 = (int *)malloc(sizeof(int)*(m+1));
    136   l = 0;
    137   m = 0;
    138   while ((-1 != iSamples[l])&&(l < j))
    139   {
    140    if (iInput[iSamples[l]][iTest_Attribute] == iAttributeValue[k])
    141    {
    142     iSamples1[m] = iSamples[l];
    143     m++;
    144    }
    145    l++;
    146   }
    147   iSamples1[m] = -1;
    148   if (-1 == iSamples1[0])
    149   {
    150    fprintf(fp,"result: %d\n",check_ordinary(iSamples));
    151    return;
    152   }
    153   fprintf(fp,"level%d: %d = %d\n",level,iTest_Attribute,iAttributeValue[k]);
    154   build_tree(fp,iSamples1,iAttribute,level+1);
    155   k++;
    156  }
    157 }
    158 int choose_attribute(int* iSamples, int* iAttribute)
    159 {
    160  int iTestAttribute = -1;
    161  int k = 0;
    162  int l = 0;
    163  int m = 0;
    164  int n = 0;
    165  int iTrue = 0;
    166  int iFalse = 0;
    167  int iTrue1 = 0;
    168  int iFalse1 = 0;
    169  int iDepart[MAX];
    170  int iRecord[MAX];
    171  double dEntropy = 0.0;
    172  double dGainratio = 0.0;
    173  double test = 0.0;
    174  
    175  for (k = 0;k<MAX;k++)
    176  {
    177   iDepart[k] = -1;
    178   iRecord[k] = 0;
    179  }
    180  k = 0;
    181  while ((l!=2)&&(k<(i - 1)))
    182  {
    183   if (iAttribute[k] == -1)
    184   {
    185    l++;
    186   }
    187   k++;
    188  }
    189  if (l == 1)
    190  {
    191   for (k = 0;k<(k-1);k++)
    192   {
    193    if (iAttribute[k] == -1)
    194    {
    195     return iAttribute[k];
    196    }
    197   }
    198  }
    199  for (k = 0;k < (i-1);k++)
    200  {
    201   l = 0;
    202   iTrue = 0;
    203   iFalse = 0;
    204   if (iAttribute[k] != -1)
    205   {
    206    while ((-1 != iSamples[l])&&(l < j))
    207    {
    208     if (0 == iInput[iSamples[l]][i-1])
    209     {
    210      iFalse++;
    211     }
    212     if (1 == iInput[iSamples[l]][i-1])
    213     {
    214      iTrue++;
    215     }
    216     l++;    
    217    }
    218    for (n = 0;n<l;n++)//计算该属性有多少不同的值并记录
    219    {
    220     m = 0;
    221     while((iDepart[m]!=-1)&&(m!=MAX))
    222     {
    223      if (iInput[iSamples[n]][iAttribute[k]] == iDepart[m])
    224      {
    225       break;
    226      }
    227      m++;
    228     }
    229     if (-1 == iDepart[m])
    230     {
    231      iDepart[m] = iInput[iSamples[n]][iAttribute[k]];
    232     }
    233    }
    234    while ((iDepart[m] != -1)&&(m!=MAX))
    235    {
    236     for (n = 0;n<l;n++)
    237     {
    238      if (iInput[iSamples[n]][iAttribute[k]] == iDepart[m])
    239      {
    240       if (1 == iInput[iSamples[n]][i-1])
    241       {
    242        iTrue1++;
    243       }
    244       if (0 == iInput[iSamples[n]][i-1])
    245       {
    246        iFalse1++;
    247       }
    248       iRecord[m]++;
    249      }
    250     }
    251     
    252     dEntropy += entropy((double)iTrue1,(double)iFalse1,(double)l);
    253     iTrue1 = 0;
    254     iFalse1 = 0;
    255     m++;
    256    }
    257    double dSplitinfo = splitinfo(iRecord,(double)l);
    258    if (-1 == iTestAttribute)
    259    {
    260     iTestAttribute = k;
    261     dGainratio = (info((double)iTrue,(double)iFalse)-dEntropy)/dSplitinfo;
    262    }
    263    else
    264    {
    265     test = (info((double)iTrue,(double)iFalse)-dEntropy)/dSplitinfo;
    266     if (dGainratio < test)
    267     {
    268      iTestAttribute = k;
    269      dGainratio = test;
    270     }
    271    }
    272   }
    273  }
    274  return iTestAttribute;
    275 }
    276 double info(double dTrue,double dFalse)
    277 {
    278  double dInfo = 0.0;
    279  dInfo = ((dTrue/(dTrue+dFalse))*(log(dTrue/(dTrue+dFalse))/log(2.0))+(dFalse/(dTrue+dFalse))*(log(dFalse/(dTrue+dFalse))/log(2.0)))*(-1);
    280  return dInfo;
    281 }
    282 double entropy(double dTrue, double dFalse, double dAll)
    283 {
    284  double dEntropy = 0.0;
    285  dEntropy = (dTrue + dFalse)*info(dTrue,dFalse)/dAll;
    286  return dEntropy;
    287 }
    288 double splitinfo(int* list,double dAll)
    289 {
    290  int k = 0;
    291  double dSplitinfo = 0.0;
    292  while (0!=list[k])
    293  {
    294   dSplitinfo -= ((double)list[k]/(double)dAll)*(log((double)list[k]/(double)dAll));
    295   k++;
    296  }
    297  return dSplitinfo;
    298 }
    299 int check_samples(int *iSamples)
    300 {
    301  int k = 0;
    302  int b = 0;
    303  while ((-1 != iSamples[k])&&(k < j-1))
    304  {
    305   if (iInput[k][i-1] != iInput[k+1][i-1])
    306   {
    307    b = 1;
    308    break;
    309   }
    310   k++;
    311  }
    312  return b;
    313 }
    314 int check_ordinary(int *iSamples)
    315 {
    316  int k = 0;
    317  int iTrue = 0;
    318  int iFalse = 0;
    319  while ((-1 != iSamples[k])&&(k < i))
    320  {
    321   if (0 == iInput[iSamples[k]][i-1])
    322   {
    323    iFalse++;
    324   }
    325   else
    326   {
    327    iTrue++;
    328   }
    329   k++;
    330  }
    331  if (iTrue >= iFalse)
    332  {
    333   return 1;
    334  }
    335  else
    336  {
    337   return 0;
    338  }
    339 }
    340 int check_attribute_null(int *iAttribute)
    341 {
    342  int k = 0;
    343  while (k < (i-1))
    344  {
    345   if (-1 != iAttribute[k])
    346   {
    347    return 0;
    348   }
    349   k++;
    350  }
    351  return 1;
    352 }
    353 void get_attributes(int *iSamples,int *iAttributeValue,int iAttribute)
    354 {
    355  int k = 0;
    356  int l = 0;
    357  while ((-1 != iSamples[k])&&(k < j))
    358  {
    359   l = 0;
    360   while (-1 != iAttributeValue[l])
    361   {
    362    if (iInput[iSamples[k]][iAttribute] == iAttributeValue[l])
    363    {
    364     break;
    365    }
    366    l++;
    367   }
    368   if (-1 == iAttributeValue[l])
    369   {
    370    iAttributeValue[l] = iInput[iSamples[k]][iAttribute];
    371   }
    372   k++;
    373  }
    374 }

    代码未验证...

  • 相关阅读:
    【C++17】std::optional

    【GDB 】GDB基本命令
    【二叉树系列 | 01】二叉树遍历
    【coredump | 01】coredump的阐述
    【C++ Template | 06】std::enable_if和SFINAE
    std::dclval 使用教程
    系统设计实践(03)- Instagram社交服务
    系统设计实践(02)- 文本存储服务
    系统设计实践(01)
  • 原文地址:https://www.cnblogs.com/94julia/p/2968627.html
Copyright © 2011-2022 走看看