机器学习算法之一(C4.5)
在机器学习中,决策树是一个预测模型:它代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分岔路径则代表的某个可能的属性值,而每个叶节点则对应从根节点到该叶节点所经历的路径所表示的值。决策树仅有单一输出,若欲有复数输出,可以建立独立的决策树以处理不同输出。
从数据产生决策树的机器学习技术叫做决策树学习,通俗说就是决策树。
决策树学习也是数据挖掘中一个普通的方法。在这里,每个决策树都表述了一种树形结构,他有他的分支来对该类型的对象依靠属性进行修剪。每个决策树可以依靠对源数据库的分割进行数据测试。这个过程可以递归式的对树进行修剪。当不能再进行分割或一个单独的类可以被应用于某一分支时,递归过程就完成了。另外,随机森林分类器将许多决策树结合起来以提升分类的正确率。
决策树同时也可以依靠计算条件概率来构造。决策树如果依靠数学的计算方法可以取得更加理想的效果。
决策树是如何工作的?
决策时一般都是自上而下的来生成的。
选择分割的方法有好几种,但是目的都是一致的:对目的尝试进行最佳的分割。
从根到叶子节点都有一条路径,这条路径就是一条“规则”。
决策树可以是二叉的,也可以是多叉的。
对每个节点的衡量:
- 通过该节点的记录数
- 如果是叶子节点的话,分类的路径
- 对叶子节点正确分类的比例
有些规则的效果可以比其他的一些规则要好。
由于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 }代码未验证...