转载自:http://blog.csdn.net/hawksoft/article/details/7760868

1、辅助类,用于计算过程和结果存储

[csharp] view plaincopyprint?
  1. /// <summary>
  2. /// 决策树节点.
  3. /// </summary>
  4. public class DecisionTreeNode
  5. {
  6. /// <summary>
  7. /// 类型:分支或叶子
  8. /// </summary>
  9. public string Type { get; set; }
  10. /// <summary>
  11. /// 关键字一般存当前属性因子
  12. /// </summary>
  13. public string Key { get; set; }
  14. /// <summary>
  15. /// 判断值,叶子节点有效.
  16. /// </summary>
  17. public string DecisionValue { get; set; }
  18. /// <summary>
  19. /// 前一个属性因子,可以看作是分支条件.
  20. /// </summary>
  21. public string ParentFactor { get; set; }
  22. /// <summary>
  23. /// 当前节点的样本数量,
  24. /// </summary>
  25. public int CalcCount { get; set; }
  26. /// <summary>
  27. /// 当前节点的样本索引集合.
  28. /// </summary>
  29. public List<int> DataIndexes {get;set;}
  30. /// <summary>
  31. /// 分支节点集合.
  32. /// </summary>
  33. public Dictionary<string, DecisionTreeNode> Children { get; private set; }
  34. /// <summary>
  35. /// 父节点
  36. /// </summary>
  37. public DecisionTreeNode Parent { get; set; }
  38. public DecisionTreeNode()
  39. {
  40. DataIndexes = new List<int>();
  41. Children = new Dictionary<string, DecisionTreeNode>();
  42. }
  43. }
  44. /// <summary>
  45. /// 用于计算过程存放数据.用数组不是很方便,这里采用字典,可以减少循环次数.
  46. /// </summary>
  47. public class CalcNode
  48. {
  49. public string Key { get; set; }
  50. public string Type { get; set; }
  51. public int CalcCount { get; set; }
  52. public List<int> DataIndexes {get;set;}
  53. public Dictionary<string, CalcNode> Children { get; private set; }
  54. public CalcNode()
  55. {
  56. DataIndexes = new List<int>();
  57. Children = new Dictionary<string, CalcNode>();
  58. }
  59. public void AddChildren(string Key,string AType,int AIndex, int Count = 1)
  60. {
  61. if (Children.ContainsKey(Key) == false)
  62. {
  63. Children.Add(Key, new CalcNode());
  64. }
  65. Children[Key].Key = Key;
  66. Children[Key].Type = AType;
  67. Children[Key].CalcCount += Count;
  68. Children[Key].DataIndexes.Add(AIndex);
  69. }
  70. }

2、算法类,注释比较详细,有时间再写一篇原理文章

[csharp] view plaincopyprint?
  1. /// <summary>
  2. /// 决策树算法类,不适合连续性值。
  3. /// </summary>
  4. public class DecisionTreeAlg
  5. {
  6. private string PrefixString = "                                                                                                                                                                                                       ";
  7. /// <summary>
  8. /// 构建决策树,决策分类属性约定放在第1列。
  9. /// </summary>
  10. /// <param name="Inputs">行表示属性,列为值,注意列等长</param>
  11. /// <param name="PNode">父节点</param>
  12. /// <param name="PropertyNames">测试属性名称</param>
  13. /// <param name="TestProperties">当前可用测试属性索引</param>
  14. /// <param name="DefaultClassFactor">缺省判别决策分类因子</param>
  15. /// <param name="CallLevel">用来测试输出控制,无实际作用</param>
  16. /// <param name="OutContents">输出内容,为调试用</param>
  17. /// <param name="PropertyFactors">属性因子</param>
  18. public void BuildDecisionTree(int CallLevel, ref string OutContents, string[][] Inputs, DecisionTreeNode PNode, string[] PropertyNames, List<int> TestProperties, string DefaultClassFactor, Dictionary<string, List<string>> PropertyFactors)
  19. {
  20. string thePrefix = PrefixString.Substring(0, CallLevel * 2);
  21. CallLevel++;
  22. //如果没有测试属性,将当前节点设为叶子节点,选择高概率分类,然后返回
  23. if (TestProperties.Count <= 1)
  24. {
  25. PNode.Type = "叶子";
  26. PNode.DecisionValue = DefaultClassFactor;
  27. return;
  28. }
  29. //如果没有学习样本集,将当前节点设为叶子节点,选择高概率分类,然后返回
  30. if (PNode.DataIndexes.Count <= 0)
  31. {
  32. PNode.Type = "叶子";
  33. PNode.DecisionValue = DefaultClassFactor;
  34. return;
  35. }
  36. if (PropertyFactors == null)
  37. {
  38. PropertyFactors = new Dictionary<string, List<string>>();
  39. }
  40. //准备存储遍历时的计数存储结构
  41. Dictionary<string, CalcNode> thePropertyCount = new Dictionary<string, CalcNode>();
  42. foreach (var theProIndex in TestProperties)
  43. {
  44. thePropertyCount.Add(PropertyNames[theProIndex], new CalcNode() { Key = PropertyNames[theProIndex] });
  45. if (PropertyFactors.ContainsKey(PropertyNames[theProIndex]) == false)
  46. {
  47. PropertyFactors.Add(PropertyNames[theProIndex], new List<string>());
  48. }
  49. }
  50. //遍历当前可遍历的数据,进行统计,为计算各属性熵做准备
  51. for (int n = 0; n < PNode.DataIndexes.Count; n++)
  52. {
  53. int theI = PNode.DataIndexes[n];
  54. for (int k = 0; k < TestProperties.Count; k++)
  55. {
  56. int theJ = TestProperties[k];
  57. var thePropertyCalcNode = thePropertyCount[PropertyNames[theJ]];
  58. //对当前属性计数
  59. thePropertyCalcNode.CalcCount++;
  60. //对第j个属性的当前因子计数
  61. thePropertyCalcNode.AddChildren(Inputs[theJ][theI], "测试属性因子", theI, 1);
  62. //对第j个属性的当前因子的主分类因子计数
  63. thePropertyCalcNode.Children[Inputs[theJ][theI]].AddChildren(Inputs[0][theI], "主分类因子", theI, 1);
  64. //统计归纳各属性因子,采用这种方式可以减少循环.
  65. if (PropertyFactors[PropertyNames[theJ]].Contains(Inputs[theJ][theI]) == false)
  66. {
  67. PropertyFactors[PropertyNames[theJ]].Add(Inputs[theJ][theI]);
  68. }
  69. }
  70. }
  71. //计算信息增益量,获取具有最大信息增益属性
  72. string theDefaultClassFactor = DefaultClassFactor;
  73. //初始化最大测试属性熵值.
  74. double theMaxEA = double.MinValue;
  75. //记录具有最大熵值属性的索引位置
  76. int theMaxPropertyIndex = TestProperties[1];
  77. //总信息熵值,其实就是分类属性的熵值.
  78. double theTotalEA = 0.0;
  79. //记录总的样本数,用于估算概率.
  80. double theTotalSimple = 0;
  81. for(int theI=0;theI<TestProperties.Count;theI++)
  82. {
  83. int thePIndex_1 = TestProperties[theI];
  84. if (thePIndex_1 == 0)
  85. {
  86. //主分类熵值计算,计算公式与测试属性有所不同.
  87. CalcNode theCalcNode = thePropertyCount[PropertyNames[thePIndex_1]];
  88. double theCount = theCalcNode.CalcCount;
  89. theTotalSimple = theCount;
  90. double theMaxSubCount = -1;
  91. theTotalEA = 0.0;
  92. //求和(-Pj*log2(Pj))
  93. foreach (var theSubNode in theCalcNode.Children)
  94. {
  95. if (theSubNode.Value.CalcCount > 0)
  96. {
  97. double thePj = theSubNode.Value.CalcCount / theCount;
  98. theTotalEA += 0 - thePj * Math.Log(thePj, 2);
  99. }
  100. if (theMaxSubCount < theSubNode.Value.CalcCount)
  101. {
  102. theMaxSubCount = theSubNode.Value.CalcCount;
  103. theDefaultClassFactor = theSubNode.Key;
  104. }
  105. //测试输出,跟踪计算路径.
  106. OutContents += "\r\n" + thePrefix + theCalcNode.CalcCount + ":: " + PropertyNames[thePIndex_1] + ":: " + theSubNode.Value.Type + " :: " + theSubNode.Key + " :: " + theSubNode.Value.CalcCount;
  107. }
  108. }
  109. else
  110. {
  111. //测试属性熵值计算。
  112. CalcNode theCalcNode = thePropertyCount[PropertyNames[thePIndex_1]];
  113. double theJEA = 0.0;
  114. foreach (var theSubNode_1 in theCalcNode.Children)
  115. {
  116. if (theSubNode_1.Value.CalcCount > 0)
  117. {
  118. double theSjCount = theSubNode_1.Value.CalcCount;
  119. double theSj_1 = theSjCount / theTotalSimple;
  120. double theSj_2 = 0.0;
  121. foreach (var theSubNode_2 in theSubNode_1.Value.Children)
  122. {
  123. if (theSubNode_2.Value.CalcCount > 0)
  124. {
  125. double thePj_1 = Convert.ToDouble(theSubNode_2.Value.CalcCount) / theSjCount;
  126. theSj_2 += 0.0 - thePj_1 * Math.Log(thePj_1, 2);
  127. }
  128. OutContents += "\r\n" + thePrefix + theCalcNode.CalcCount + ":: " + PropertyNames[thePIndex_1] + " :: " + theSubNode_1.Value.Type + " :: " + theSubNode_1.Key + " :: " + theSubNode_1.Value.CalcCount
  129. + theSubNode_2.Value.Type + " :: "  + theSubNode_2.Key + " :: " + theSubNode_2.Value.CalcCount;
  130. }
  131. theJEA += theSj_1 * theSj_2;
  132. }
  133. }
  134. theJEA = theTotalEA - theJEA;
  135. //只记录最大熵值属性信息.
  136. if (theMaxEA < theJEA)
  137. {
  138. theMaxEA = theJEA;
  139. theMaxPropertyIndex = thePIndex_1;
  140. }
  141. }
  142. }
  143. //如果分类因子只有一个,则置当前节点为叶子节点,设置判定为当前分类因子,然后返回
  144. if (thePropertyCount[PropertyNames[0]].Children.Count <= 1)
  145. {
  146. PNode.Type = "叶子";
  147. PNode.DecisionValue = theDefaultClassFactor;
  148. return;
  149. }
  150. //具有多个分类因子,还剩有测试属性,则设当前节点为分支节点,准备分支.
  151. PNode.Type = "分支";
  152. //1选取最大增益信息量测试属性,做分支处理,做处理,注意属性一旦处理,将不在后续节点中再处理
  153. //因此需要在测试属性集合中删除所选测试属性.注意保持分类属性在开始索引处(0).
  154. PNode.Key = PropertyNames[theMaxPropertyIndex];
  155. CalcNode theCalcNode_2 = thePropertyCount[PropertyNames[theMaxPropertyIndex]];
  156. List<string> theFactors = PropertyFactors[PropertyNames[theMaxPropertyIndex]];
  157. List<int> theAvailableTestPs = new List<int>();
  158. for (int i = 0; i < TestProperties.Count; i++)
  159. {
  160. if (theMaxPropertyIndex != TestProperties[i])
  161. {
  162. theAvailableTestPs.Add(TestProperties[i]);
  163. }
  164. }
  165. //对所选测试属性的所有因子进行处理.
  166. foreach (var theFactor_1 in theFactors)
  167. {
  168. //如果当前因子不在计算中,则添加一个叶子节点,判定为高概率分类。
  169. if (theCalcNode_2.Children.ContainsKey(theFactor_1) == false)
  170. {
  171. DecisionTreeNode theNode_1 = new DecisionTreeNode();
  172. theNode_1.ParentFactor = theFactor_1;
  173. theNode_1.CalcCount = 0;
  174. theNode_1.DecisionValue = theDefaultClassFactor;
  175. theNode_1.Parent = PNode;
  176. theNode_1.Key = theFactor_1;
  177. theNode_1.Type = "叶子";
  178. PNode.Children.Add(theFactor_1, theNode_1);
  179. continue;
  180. }
  181. //如果当前因子存在,但不存在样本,则添加一个叶子节点,判定为高概率分类。
  182. if (theCalcNode_2.Children[theFactor_1].CalcCount<=0)
  183. {
  184. DecisionTreeNode theNode_1 = new DecisionTreeNode();
  185. theNode_1.ParentFactor = theFactor_1;
  186. theNode_1.CalcCount = 0;
  187. theNode_1.DecisionValue = theDefaultClassFactor;
  188. theNode_1.Parent = PNode;
  189. theNode_1.Type = "叶子";
  190. theNode_1.Key = theFactor_1;
  191. PNode.Children.Add(theFactor_1, theNode_1);
  192. continue;
  193. }
  194. //如果存在,且有学习样本,则添加一个节点,并以此节点递归处理.
  195. DecisionTreeNode theNode_2 = new DecisionTreeNode();
  196. theNode_2.ParentFactor = theFactor_1;
  197. theNode_2.Parent = PNode;
  198. theNode_2.Key = theFactor_1;
  199. theNode_2.CalcCount = theCalcNode_2.Children[theFactor_1].CalcCount;
  200. theNode_2.DataIndexes.AddRange(theCalcNode_2.Children[theFactor_1].DataIndexes);
  201. PNode.Children.Add(theFactor_1, theNode_2);
  202. BuildDecisionTree(CallLevel, ref OutContents, Inputs, theNode_2, PropertyNames, theAvailableTestPs, theDefaultClassFactor, PropertyFactors);
  203. }
  204. }
  205. }

3、测试代码:

[csharp] view plaincopyprint?
  1. private void button1_Click(object sender, EventArgs e)
  2. {
  3. DecisionTreeAlg theAlg = new DecisionTreeAlg();
  4. string[][] theInputs = new string[4][];
  5. theInputs[0] = new string[] { "no", "yes", "yes", "yes", "yes", "yes", "no", "yes", "yes", "no" };
  6. theInputs[1] = new string[] { "s", "s", "l", "m", "l", "m", "m", "l", "m", "s" };
  7. theInputs[2] = new string[] { "s", "l", "m", "m", "m", "l", "s", "m", "s", "s" };
  8. theInputs[3] = new string[] { "no", "yes", "yes", "yes", "no", "no", "no", "no", "no", "yes" };
  9. string[] thePropertyName = new string[] {"是否真实帐号","日志密度","好友密度","是否真实头像" };
  10. DecisionTreeNode theRootNode = new DecisionTreeNode();
  11. theRootNode.DataIndexes.AddRange(new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
  12. List<int> theTestPs = new List<int>() { 0, 1, 2, 3 };
  13. string theOuts = "";
  14. theAlg.BuildDecisionTree(0,ref theOuts, theInputs, theRootNode, thePropertyName, theTestPs, "", null);
  15. this.treeView1.Nodes.Clear();
  16. TreeNode theRoot = new TreeNode();
  17. this.treeView1.Nodes.Add(theRoot);
  18. VisitTree(theRoot, theRootNode);
  19. this.textBox1.Text = theOuts;
  20. }
  21. private void VisitTree(TreeNode PNode, DecisionTreeNode PDNode)
  22. {
  23. PNode.Text = PDNode.Key + "(" + PDNode.Type + ")[判定:"+PDNode.DecisionValue +"]";
  24. foreach (var theNode in PDNode.Children.Values)
  25. {
  26. TreeNode theTmpNode = new TreeNode();
  27. PNode.Nodes.Add(theTmpNode);
  28. VisitTree(theTmpNode, theNode);
  29. }
  30. }

R语言学习系列(数据挖掘之决策树算法实现--ID3代码篇)相关推荐

  1. R语言学习系列之本地数据获取

    R语言学习系列之本地数据获取 任何数据分析工作之前,都得把数据先读取进来你才能进行后续的分析工作.所以本文简要介绍在R中如何对本地文件进行获取,希望可以给刚刚接触R语言的同学一点启发. 一.控制台的输 ...

  2. R语言学习系列之向量化计算

    ##R语言学习系列之向量化计算 本文主要讲解R语言向量化计算的原理及方法,希望对初学者能够提供帮助. ##一.向量化 什么是向量化计算呢?其实你可以简单的理解成这样:当我们在使用函数或者定义函数的时候 ...

  3. R语言学习系列教程及高级绘图工具使用

    R语言系列教程 引言:每天学点R语言 R语言的安装 Rstudio的安装和运行 R语言常用语法代码示例 R语言数据导入测试代码及数据 R语言数据操作示例及数据 R语言数据操作进阶及控制结构 R语言中处 ...

  4. R语言学习路径和感受

    第一次接触R语言是我读研的时候,算到现在有5年多了.R语言可以算得上是我进入编程世界的启蒙语言,尽管在大学期间为了考试而被迫学习过计算机二级,但那真心是没有一丁点的兴趣可言.进入R的世界后,真的越来越 ...

  5. R语言学习笔记(1~3)

    R语言学习笔记(1~3) 一.R语言介绍 x <- rnorm(5) 创建了一个名为x的向量对象,它包含5个来自标准正态分布的随机偏差. 1.1 注释 由符号#开头. #函数c()以向量的形式输 ...

  6. R语言学习手记 (1)

    R语言学习手记 (1) 经管的会计和财管都会学数据统计与分析R语言这门课,加上我也有点兴趣,就提前选了这门课,以下的笔记由老师上课的PPT.<R语言编程艺术>和<R语言数据科学> ...

  7. R语言学习笔记——入门篇:第一章-R语言介绍

    R语言 R语言学习笔记--入门篇:第一章-R语言介绍 文章目录 R语言 一.R语言简介 1.1.R语言的应用方向 1.2.R语言的特点 二.R软件的安装 2.1.Windows/Mac 2.2.Lin ...

  8. Ruby语言学习系列--基本的ruby语法

    Ruby语言学习系列--基本的ruby语法 1.     基本的ruby语法 1.1      变量.常量和类型 1)      定义变量 变量类型 描述 示例 局部变量(或伪变量) 以小写字母或下划 ...

  9. 2021年R语言学习路线以及资源推荐

    R语言学习从入门到熟练掌握资源推荐 最近有些小伙伴在后台问我要一些资源,呃,前段时间一直没看到消息,现在统一整理一下,由于微信不让发这个,我就放在公众号里了,在公众号里回复[R语言学习资源]即可,如果 ...

最新文章

  1. centos使用yum快速安装java的方法
  2. 《LeetCode力扣练习》第55题 跳跃游戏 Java
  3. oracle 查看任务数量,关于dbms_scheduler创建任务数量的疑问
  4. delphi xe2 project菜单怎么没有加组件功能_交互设计:让人困惑的三大交互组件及用法...
  5. Linux安装中文总是提示失败,AnyBackup-Linux 客户端安装失败,提示错误信息:Self IP Address is invalid...
  6. 实时语义分割算法大盘点
  7. VMware Workstation 11网络桥接可以通,NAT不能与主机通信解决办法
  8. STM32F103ZET6 GPIO的使用
  9. Java实验9 T5. 给当前的类文件添加行号拷贝到txt文件
  10. 解决混合模式程序集在VS2010 .net 4.0 环境下调试出错的方法。
  11. MOSS自带链接样式影响页面全局样式的解决办法
  12. html字体样式(有中文兼英文实例)
  13. vue - vue项目使用BOS (百度云对象存储)上传文件
  14. 《17.Deep Pyramidal Residual Networks》
  15. pandas文件保存操作
  16. SRAM随机存储器的特点及结构
  17. 转载--我的AI转型之路与AI之我见(非985211的奋斗路程与视角)
  18. Linux虚拟机连接外网
  19. pvq真值表_真值表等数理逻辑方法的判定功能
  20. 保姆级-MySQL 8.0的下载、安装、配置

热门文章

  1. Android Studio解决:Caused by: org.gradle.api.internal.plugins.PluginApplicationException: Failed
  2. H264/H265之NALU结构(三)
  3. nginx之反向代理配置
  4. Abseil之拆分字符串
  5. Tensorflow2.0:使用Keras自定义网络实战
  6. 推荐一款wordpress个人博客主题,中文版主题
  7. oraclemt 无法启动服务_调整MT后台 解决站点压力问题
  8. html加载富文本_富文本图片懒加载解决方案
  9. golang interface 类型转换_Golang面试题41道
  10. idea与myeclipse或eclipse使用编译时的区别