机器学习算法之一(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 }

代码未验证...

原文地址:https://www.cnblogs.com/94julia/p/2968627.html