一、决策树简介:

关于决策树,几乎是数据挖掘分类算法中最先介绍到的。

决策树,顾名思义就是用来做决定的树,一个分支就是一个决策过程。

每个决策过程中涉及一个数据的属性,而且只涉及一个。然后递归地,贪心地直到满足决策条件(即可以得到明确的决策结果)。

决策树的实现首先要有一些先验(已经知道结果的历史)数据做训练,通过分析训练数据得到每个属性对结果的影响的大小,这里我们通过一种叫做信息增益的理论去描述它,期间也涉及到的概念。也可参考文章信息增益与熵.

下面我们结合实例说一下决策树实现过程中的上述关键概念:

假设我们有如下数据:

age job house credit class
1 0 0 1 0
1 0 0 2 0
1 1 0 2 1
1 1 1 1 1
1 0 0 1 0
2 0 0 1 0
2 0 0 2 0
2 1 1 2 1
2 0 1 3 1
2 0 1 3 1
3 0 1 3 1
3 0 1 2 1
3 1 0 2 1
3 1 0 3 1
3 0 0 1 0

(一)

我们首先要通过计算找到哪个属性的所有属性值能更好地表达class字段的不同。通过计算,我们发现house的属性值最能表现class字段的不同。这个衡量标准其实就是信息增益。计算方法是:首先计算全部数据的,然后除class之外的其他属性逐个遍历,找到最小的那个属性(house),然后将全部数据的减去按照house属性划分数据之后的数据的

这个值如果满足条件假如(>0.1),我们认为数据应该按照这个节点进行分裂,也就是说这个属性(house)构成了我们的一次决策过程。

(二)

然后

在按照house分裂的每个数据集上,针对其他属性(house除外)进行与(一)相同的过程,直到信息增益不足以满足数据分裂的条件。

这样,我们就得到了一个关于属性数据划分的一棵树。可以作为class字段未知的数据的决策依据。

二、决策树代码实现:

具体计算代码如下:---假设上述数据我们保存为descision.dat文件,以及需要bash4.0及以上支持运行。

  1. #!/home/admin/bin/bash_bin/bash_4
  2. input=$1;
  3. if [ -z $input ]; then
  4. echo "please input the traning file";
  5. exit 1;
  6. fi
  7. ## pre calculate the log2 value for the later calculate operation
  8. declare -a log2;
  9. logi=0;
  10. records=$(cat $input | wc -l);
  11. for i in `awk -v n=$records 'BEGIN{for(i=1;i<n;i++) print log(i)/log(2);}'`
  12. do
  13. ((logi+=1));
  14. log2[$logi]=$i;
  15. done
  16. ## function for calculating the entropy for the given distribution of the class
  17. function getEntropy {
  18. local input=`echo $1`;
  19. if [[ $input == *" "* ]]; then
  20. local current_entropy=0;
  21. local sum=0;
  22. local i;
  23. for i in $input
  24. do
  25. ((sum+=$i));
  26. current_entropy=$(awk -v n=$i -v l=${log2[$i]} -v o=$current_entropy 'BEGIN{print n*l+o}');
  27. done
  28. current_entropy=$(awk -v n=$current_entropy -v b=$sum -v l=${log2[$sum]} 'BEGIN{print n/b*-1+l;}')
  29. eval $2=$current_entropy;
  30. else
  31. eval $2=0;
  32. fi
  33. }
  34. ### the header title of the input data
  35. declare -A header_info;
  36. header=$(head -1 $input);
  37. headers=(${header//,/ })
  38. length=${#headers[@]};
  39. for((i=0;i<length;i++))
  40. do
  41. attr=${headers[$i]};
  42. header_info[$attr]=$i;
  43. done
  44. ### the data content of the input data
  45. data=${input}_dat;
  46. sed -n '2,$p' $input > $data
  47. ## use an array to store the information of a descision tree
  48. ## the node structure is {child,slibling,parent,attr,attr_value,leaf,class}
  49. ## the root is a virtual node with none used attribute
  50. ## only the leaf node has class flag and the "leaf,class" is meaningfull
  51. ## the descision_tree
  52. declare -a descision_tree;
  53. ## the root node with no child\slibing and anythings else
  54. descision_tree[0]="0:0:0:N:N:0:0";
  55. ## use recursive algrithm to build the tree
  56. ## so we need a trace_stack to record the call level infomation
  57. declare -a trace_stack;
  58. ## push the root node into the stack
  59. trace_stack[0]=0;
  60. stack_deep=1;
  61. ## begin to build the tree until the trace_stack is empty
  62. while [ $stack_deep -ne 0 ]
  63. do
  64. ((stack_deep-=1));
  65. current_node_index=${trace_stack[$stack_deep]};
  66. current_node=${descision_tree[$current_node_index]};
  67. current_node_struct=(${current_node//:/ });
  68. ## select the current data set
  69. ## get used attr and their values
  70. attrs=${current_node_struct[3]};
  71. attrv=${current_node_struct[4]};
  72. declare -a grepstra=();
  73. if [ $attrs != "N" ];then
  74. attr=(${attrs//,/ });
  75. attrvs=(${attrv//,/ });
  76. attrc=${#attr[@]};
  77. for((i=0;i<attrc;i++))
  78. do
  79. a=${attr[$i]};
  80. index=${header_info[$a]};
  81. grepstra[$index]=${attrvs[$i]};
  82. done
  83. fi
  84. for((i=0;i<length;i++))
  85. do
  86. if [ -z ${grepstra[$i]} ]; then
  87. grepstra[$i]=".*";
  88. fi
  89. done
  90. grepstrt=${grepstra[*]};
  91. grepstr=${grepstrt// /,};
  92. grep $grepstr $data > current_node_data
  93. ## calculate the entropy before split the records
  94. entropy=0;
  95. input=`cat current_node_data | cut -d "," -f 5 | sort | uniq -c | sed 's/^ \+//g' | cut -d " " -f 1`
  96. getEntropy "$input" entropy;
  97. ## calculate the entropy for each of the rest attrs
  98. ## and select the min one
  99. min_attr_entropy=1;
  100. min_attr_name="";
  101. min_attr_index=0;
  102. for((i=0;i<length-1;i++))
  103. do
  104. ## just use the rest attrs
  105. if [[ "$attrs" != *"${headers[$i]}"* ]]; then
  106. ## calculate the entropy for the current attr
  107. ### get the different values for the headers[$i]
  108. j=$((i+1));
  109. cut -d "," -f $j,$length current_node_data > tmp_attr_ds
  110. dist_values=`cut -d , -f 1 tmp_attr_ds | sort | uniq -c | sed 's/^ \+//g' | sed 's/ /,/g'`;
  111. totle=0;
  112. totle_entropy_attr=0;
  113. for k in $dist_values
  114. do
  115. info=(${k//,/ });
  116. ((totle+=${info[0]}));
  117. cur_class_input=`grep "^${info[1]}," tmp_attr_ds | cut -d "," -f 2 | sort | uniq -c | sed 's/^ \+//g' | cut -d " " -f 1`
  118. cur_attr_value_entropy=0;
  119. getEntropy "$cur_class_input" cur_attr_value_entropy;
  120. totle_entropy_attr=$(awk -v c=${info[0]} -v e=$cur_attr_value_entropy -v o=$totle_entropy_attr 'BEGIN{print c*e+o;}');
  121. done
  122. attr_entropy=$(awk -v e=$totle_entropy_attr -v c=$totle 'BEGIN{print e/c;}');
  123. if [ $(echo "$attr_entropy < $min_attr_entropy" | bc) = 1 ]; then
  124. min_attr_entropy=$attr_entropy;
  125. min_attr_name="${headers[$i]}";
  126. min_attr_index=$j;
  127. fi
  128. fi
  129. done
  130. ## calculate the gain between the original entropy of the current node
  131. ## and the entropy after split by the attribute which has the min_entropy
  132. gain=$(awk -v b=$entropy -v a=$min_attr_entropy 'BEGIN{print b-a;}');
  133. ## when the gain is large than 0.1 and  then put it as a branch
  134. ##      and add the child nodes to the current node and push the index to the trace_stack
  135. ## otherwise make it as a leaf node and get the class flag
  136. ##      and do not push trace_stack
  137. if [ $(echo "$gain > 0.1" | bc)  = 1 ]; then
  138. ### get the attribute values
  139. attr_values_str=`cut -d , -f $min_attr_index current_node_data | sort | uniq`;
  140. attr_values=($attr_values_str);
  141. ### generate the node and add to the tree and add their index to the trace_stack
  142. tree_store_length=${#descision_tree[@]};
  143. current_node_struct[0]=$tree_store_length;
  144. parent_node_index=$current_node_index;
  145. attr_value_c=${#attr_values[@]};
  146. for((i=0;i<attr_value_c;i++))
  147. do
  148. tree_store_length=${#descision_tree[@]};
  149. slibling=0;
  150. if [ $i -lt $((attr_value_c-1)) ]; then
  151. slibling=$((tree_store_length+1));
  152. fi
  153. new_attr="";
  154. new_attrvalue="";
  155. if [ $attrs != "N" ]; then
  156. new_attr="$attrs,$min_attr_name";
  157. new_attrvalue="$attrv,${attr_values[$i]}";
  158. else
  159. new_attr="$min_attr_name";
  160. new_attrvalue="${attr_values[$i]}";
  161. fi
  162. new_node="0:$slibling:$parent_node_index:$new_attr:$new_attr_value:0:0";
  163. descision_tree[$tree_store_length]="$new_node";
  164. trace_stack[$stack_deep]=$tree_store_length;
  165. ((stack_deep+=1));
  166. done
  167. current_node_update=${current_node_struct[*]};
  168. descision_tree[$current_node_index]=${current_node_update// /:};
  169. else   ## current node is a leaf node
  170. current_node_struct[5]=1;
  171. current_node_struct[6]=`cut -d , -f $length current_node_data | sort | uniq -c | sort -n -r | head -1 | sed 's/^ \+[^ ]* //g'`;
  172. current_node_update=${current_node_struct[*]};
  173. descision_tree[$current_node_index]=${current_node_update// /:};
  174. fi
  175. ## output the descision tree after every step for split or leaf node generater
  176. echo ${descision_tree[@]};
  177. done

执行代码:

  1. ./descision.sh descision.dat

执行结果为:

  1. 1:0:0:N:N:0:0 0:2:0:house:0:0:0 0:0:0:house:1:0:0
  2. 1:0:0:N:N:0:0 0:2:0:house:0:0:0 0:0:0:house:1:1:1
  3. 1:0:0:N:N:0:0 3:2:0:house:0:0:0 0:0:0:house:1:1:1 0:4:1:house,job:0,0:0:0 0:0:1:house,job:0,1:0:0
  4. 1:0:0:N:N:0:0 3:2:0:house:0:0:0 0:0:0:house:1:1:1 0:4:1:house,job:0,0:0:0 0:0:1:house,job:0,1:1:1
  5. 1:0:0:N:N:0:0 3:2:0:house:0:0:0 0:0:0:house:1:1:1 0:4:1:house,job:0,0:1:0 0:0:1:house,job:0,1:1:1

输出结果中展示了决策树结构生成过程的细节,以及生成过程中树的变化过程

本代码中使用了一维数组结构来存储整棵决策树,输出的先后顺序按照数组下标输出。

输出结果中最后一行表示最终的决策树。它表示的树形结构其实是:

这样看着是不是就爽多了。

说明:

关于上述决策树结果中其实有部分存在误导:

默认根节点是放在数组的第一个位置的,即索引值为0,而子节点中的child与sibling为0时并不表示指向跟节点,而是表示无意义,即没有子节点或兄弟节点。

该决策树所代表的分类规则:

根据该决策树输出,我们挖掘的规则是这样的:

首先根据house属性判断,当house属性为1时,走到索引为2的节点,此时该节点是叶子节点,预测值class为1.

当house属性为0时,接着按照job属性来判断,当job属性为0时走到索引为3的节点,预测值class为0。如果job属性为1时走到索引值为4的节点,此时预测值class为1.

数据挖掘中 决策树算法实现——Bash的更多相关文章

  1. sklearn中决策树算法DesiciontTreeClassifier()调用以及sklearn自带的数据包sklearn.datasets.load_iris()的应用

    决策树方法的简单调用记录一下 clf=tree.DecisionTreeClassifier() dataMat=[];labelMat=[] dataPath='D:/machinelearning ...

  2. ID3和C4.5分类决策树算法 - 数据挖掘算法(7)

    (2017-05-18 银河统计) 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来判断其可行性的决策分析方法,是直观运用概率分析的一种图解法.由于这种决策分支画 ...

  3. 《BI那点儿事》Microsoft 决策树算法

    Microsoft 决策树算法是由 Microsoft SQL Server Analysis Services 提供的分类和回归算法,用于对离散和连续属性进行预测性建模.对于离散属性,该算法根据数据 ...

  4. ID3决策树算法原理及C++实现(其中代码转自别人的博客)

    分类是数据挖掘中十分重要的组成部分.分类作为一种无监督学习方式被广泛的使用. 之前关于"数据挖掘中十大经典算法"中,基于ID3核心思想的分类算法C4.5榜上有名.所以不难看出ID3 ...

  5. 决策树算法的Python实现—基于金融场景实操

    决策树是最经常使用的数据挖掘算法,本次分享jacky带你深入浅出,走进决策树的世界 基本概念 决策树(Decision Tree) 它通过对训练样本的学习,并建立分类规则,然后依据分类规则,对新样本数 ...

  6. 吴裕雄--天生自然python机器学习:决策树算法

    我们经常使用决策树处理分类问题’近来的调查表明决策树也是最经常使用的数据挖掘算法. 它之所以如此流行,一个很重要的原因就是使用者基本上不用了解机器学习算法,也不用深究它 是如何工作的. K-近邻算法可 ...

  7. scikit-learn决策树算法类库使用小结

    之前对决策树的算法原理做了总结,包括决策树算法原理(上)和决策树算法原理(下).今天就从实践的角度来介绍决策树算法,主要是讲解使用scikit-learn来跑决策树算法,结果的可视化以及一些参数调参的 ...

  8. 4-Spark高级数据分析-第四章 用决策树算法预测森林植被

    预测是非常困难的,更别提预测未来. 4.1 回归简介 随着现代机器学习和数据科学的出现,我们依旧把从“某些值”预测“另外某个值”的思想称为回归.回归是预测一个数值型数量,比如大小.收入和温度,而分类则 ...

  9. 就是要你明白机器学习系列--决策树算法之悲观剪枝算法(PEP)

    前言 在机器学习经典算法中,决策树算法的重要性想必大家都是知道的.不管是ID3算法还是比如C4.5算法等等,都面临一个问题,就是通过直接生成的完全决策树对于训练样本来说是“过度拟合”的,说白了是太精确 ...

随机推荐

  1. 什么是 "use strict"? 使用它的好处和坏处分别是什么?

    ECMAscript 5添加了第二种运行模式:"严格模式"(strict mode).顾名思义,这种模式使得Javascript在更严格的条件下运行. 设立"严格模式&q ...

  2. Codeforces Round #258 (Div. 2) . Sort the Array 贪心

    B. Sort the Array 题目连接: http://codeforces.com/contest/451/problem/B Description Being a programmer, ...

  3. STM32 TIMER DIAGRAM

  4. Golang Vendor 包管理工具 glide 使用教程

    Glide 是 Golang 的 Vendor 包管理器,方便你管理 vendor 和 verdor 包.类似 Java 的 Maven,PHP 的 Composer. Github:https:// ...

  5. hibernate对查询的几个知识点

    1.      query里面的主要方法 list()可以得到查询的结果集 uniqueResult()如果查询的结果只有一条可以用这个   通过这两句可以实现分页,好处是可以跨数据库 query.s ...

  6. 移植Python2到TQ2440

    环境 Python:2.7.13 开发板: TQ2440 工具链: arm-none-linux-gnueabi-gcc 4.8.3 概述 前面已经把Python3移植到TQ2440上面的,现在我们移 ...

  7. 解决Python交叉编译后,键盘方向键乱码的问题

    参考 http://www.alliedjeep.com/38071.htm https://www.zhihu.com/question/21518507 http://professor.blog ...

  8. Delphi处理Android的路径信息

    路径操作就使用TPath的方法都很方便.usesSystem.IoUtilsTPath.GetTempPath//临时目录TPath.GetCameraPath//照相机目录(照片/录像)TPath. ...

  9. 利用Ffmpeg获得flv视频缩略图和视频时间的代码

    问题描述:获得flv视频的缩略图和视频时间长度 谷歌了半天发现可以使用Ffmpeg获得视频的一些信息,先介绍一下FFMEPG 这里简单说一下:FFmpeg是用于录制.转换和流化音频和视频的完整解决方案 ...

  10. windows nginx出现 was not signaled for 5s的看过来

    windows下 nginx 配置ssl的key是不能存储密码的,否则启动时会提示输入密码 输入后也启动不起来,会报错: 2011/04/18 09:49:09 [alert] 1992#4548: ...