PART 决策树算法是一种由 WEKA 的作者 Eibe Frank 和 lan H. Witten 在1998年发明的算法,他们在1998年发表了论文Generating accurate rules sets without global optimization 详细地介绍了PART决策树的原理,并在WEKA中完整地实现了PART决策树。由于之前的股票数据挖掘的决策树部分就是用的这个算法,所以看了源代码,涉及的类比较多,贴上主要的一部分。

PART决策树实际上是一种利用不完整的决策树在数据集中提取规则的算法。算法最初的原理来源于割治的思想:先建立一条规则,将规则所覆盖的实例去除,然后递归为剩余的实例建立规则,直至没有剩余的实例。而创建一条规则的过程就是在当前的实例集上创建一个完整的决策树,然后将覆盖实例数最多的叶子节点转化成一条规则,然后丢弃这个决策树。
     上述的方法看上去是一个效率很低的算法,但是可以通过优化,使程序加速。关键的思路在于建立局部决策树而不展开整棵树。局部决策树将建树和修剪合为一体,从而得到一个简化后的子树,从简化后的子树中读出一条规则来,并停止建树的过程。

这个算法对比其他规则形成方法,它的主要优势在于简便,因为其他方法需要采用全局优化才能达到相当的性能水准。对于我们的股票数据挖掘而言,这个算法既利用了决策树的特性,又能直接生成规则,相比其他算法而言,省去了我们从决策树提取规则的步骤,且由于我们的数据集较大,算法的性能对于我们来说十分重要,所以PART决策树算法的高性能也是我们选择它的重要原因之一。

/** weka.classifiers.rules.PART类 */ /** 主要变量:*/ /** 决策树句柄 */ private MakeDecList m_root; /** 置信度 */ private float m_CF = 0.25f; /** 分裂参数 */ private int m_minNumObj = 2; /** 是否使用后剪枝 */ private boolean m_reducedErrorPruning = false; /** 使用独立的数据集修剪的时候把原始数据划分的折数 */ private int m_numFolds = 3; /** 是否对名词属性进行二元划分 */ private boolean m_binarySplits = false; /** 是否生成未修剪的树的列表 */ private boolean m_unpruned = false; /** 随机化种子 */ private int m_Seed = 1; /** 主要函数:*/ public void buildClassifier(Instances instances) throws Exception { // 验证数据类型是否为算法所支持的类型 getCapabilities().testWithFail(instances); // 读入数据集中的数据 data = new Instances(data); // 删除不完整的数据 data.deleteWithMissingClass(); // 创建一个决策树模型选择实例 ModelSelection modSelection; // 对决策树模型进行选择 // 是否要对名词属性进行二元划分 if (m_binarySplits) modSelection = new BinC45ModelSelection(m_minNumObj, instances); else modSelection = new C45ModelSelection(m_minNumObj, instances); // 是否生成未修剪的树的列表 if (m_unpruned) m_root = new MakeDecList(modSelection, m_minNumObj); // 如果要进行后剪枝 else if (m_reducedErrorPruning) m_root = new MakeDecList(modSelection, m_numFolds, m_minNumObj, m_Seed); else m_root = new MakeDecList(modSelection, m_CF, m_minNumObj); // 创建决策树 m_root.buildClassifier(instances); // 对于任何决策树模型,设置初始数据集为空 if (m_binarySplits) { ((BinC45ModelSelection)modSelection).cleanup(); } else { ((C45ModelSelection)modSelection).cleanup(); } } /** weka.classifiers.rules.MakeDecList类 */ /** 主要函数:*/ public void buildClassifier(Instances data) throws Exception { // 验证数据类型是否为算法所支持的类型 getCapabilities().testWithFail(data); // 读入数据集中的数据 data = new Instances(data); // 删除不完整的数据 data.deleteWithMissingClass(); ClassifierDecList currentRule; double currentWeight; Instances oldGrowData, newGrowData, oldPruneData, newPruneData; // 规则的条数 int numRules = 0; // 为储存规则的容器开辟空间 theRules = new Vector(); // 如果要进行后剪枝 if ((reducedErrorPruning) && !(unpruned)){ // 生成随机数 Random random = new Random(m_seed); // 重新排列数据 data.randomize(random); // 将数据按类排序后分成numSetS层 data.stratify(numSetS); // 将训练集实例平均分为numSetS个集合,取训练集的最后一个作为决策树的训练集 oldGrowData = data.trainCV(numSetS, numSetS - 1, random); // 将测试集实例平均分为numSetS个集合,取测试集的最后一个作为决策树的测试集 oldPruneData = data.testCV(numSetS, numSetS - 1); // 如果不进行后剪枝 } else { // 所有实例都是训练集 oldGrowData = data; // 不需要测试集 oldPruneData = null; } // 如果还有实例没有被规则覆盖就继续 while (Utils.gr(oldGrowData.numInstances(),0)){ // 如果需要生成未修剪的树 if (unpruned) { currentRule = new ClassifierDecList(toSelectModeL,minNumObj); ((ClassifierDecList)currentRule).buildRule(oldGrowData); // 如果要进行后剪枝 } else if (reducedErrorPruning) { currentRule = new PruneableDecList(toSelectModeL, minNumObj); ((PruneableDecList)currentRule).buildRule(oldGrowData, oldPruneData); // 其他情况 } else { currentRule = new C45PruneableDecList(toSelectModeL, CF, minNumObj); ((C45PruneableDecList)currentRule).buildRule(oldGrowData); } numRules++; // 在实例中删除已经被规则覆盖的所有实例 newGrowData = new Instances(oldGrowData,oldGrowData.numInstances()); Enumeration enu = oldGrowData.enumerateInstances(); while (enu.hasMoreElements()) { Instance instance = (Instance) enu.nextElement(); currentWeight = currentRule.weight(instance); if (Utils.sm(currentWeight,1)) { instance.setWeight(instance.weight()*(1-currentWeight)); newGrowData.add(instance); } } newGrowData.compactify(); oldGrowData = newGrowData; // 如果树是需要后修剪的,还要从测试集中删除已经被规则覆盖的所有实例 if ((reducedErrorPruning) && !(unpruned)) { newPruneData = new Instances(oldPruneData,oldPruneData.numInstances()); enu = oldPruneData.enumerateInstances(); while (enu.hasMoreElements()) { Instance instance = (Instance) enu.nextElement(); currentWeight = currentRule.weight(instance); if (Utils.sm(currentWeight,1)) { instance.setWeight(instance.weight()*(1-currentWeight)); newPruneData.add(instance); } } newPruneData.compactify(); oldPruneData = newPruneData; } // 储存生成的新规则 theRules.addElement(currentRule); } } /** weka.classifiers.rules.part.ClassifierDecList类 */ /** 主要变量:*/ /** 计算熵 */ protected static EntropySplitCrit m_splitCrit = new EntropySplitCrit(); /** 决策树模型 */ protected ModelSelection m_toSelectModel; /** 决策树的分裂模型 */ protected ClassifierSplitModel m_localModel; /** 所有的子节点 */ protected ClassifierDecList [] m_sons; /** 节点是否为叶子节点 */ protected boolean m_isLeaf; /** 节点是否为空 */ protected boolean m_isEmpty; /** 训练集 */ protected Instances m_train; /** 测试集 */ protected Distribution m_test; /** 要扩展的子节点下标 */ protected int indeX; /** 主要函数:*/ public void buildDecList(Instances data, boolean leaf) throws Exception { Instances [] localInstances,localPruneInstances; int index,ind; int i,j; double sumOfWeights; NoSplit noSplit; // 初始训练集为空 m_train = null; // 初始测试集为空 m_test = null; // 初始节点不是叶子节点 m_isLeaf = false; // 初始节点不是空节点 m_isEmpty = false; // 初始节点没有子节点 m_sons = null; // 子节点下标初始为0 indeX = 0; sumOfWeights = data.sumOfWeights(); // 取得已经不再分裂的模式 noSplit = new NoSplit (new Distribution((Instances)data)); // 如果当前节点是叶子节点则不再分裂 if (leaf) m_localModel = noSplit; // 如果不是叶子节点则选择最合适的决策树模型 else m_localModel = m_toSelectModel.selectModel(data); // 如果子集数大于一则继续分裂 if (m_localModel.numSubsets() > 1) { // 按照选出的模型分裂数据集 localInstances = m_localModel.split(data); // 清空原数据集 data = null; // 按照分裂成的子节点个数开辟空间 m_sons = new ClassifierDecList [m_localModel.numSubsets()]; i = 0; do { i++; // 找到最小熵的下标 ind = chooseIndex(); // 如果没有找到可以产生信息增益的节点 if (ind == -1) { // 遍历每个子节点,如果节点为空,则将它设置为叶子节点 for (j = 0; j < m_sons.length; j++) if (m_sons[j] == null) m_sons[j] = getNewDecList(localInstances[j],true); // 如果当前节点无法再分裂 if (i < 2) { // 模型设置为不再分裂 m_localModel = noSplit; // 当前节点为叶子节点 m_isLeaf = true; // 当前节点没有子节点 m_sons = null; // 如果没有数据则当前节点为空节点 if (Utils.eq(sumOfWeights,0)) m_isEmpty = true; return; } ind = 0; break; // 找到最小熵的下标,递归继续分裂 } else m_sons[ind] = getNewDecList(localInstances[ind],false); // 如果没有遍历完子节点且遍历过的子节点全是根节点则继续遍历 } while ((i < m_sons.length) && (m_sons[ind].m_isLeaf)); // 建立规则 // 返回子节点中含有最多样本的下标 indeX = chooseLastIndex(); // 如果子集数不大于1 }else{ // 节点为叶子节点 m_isLeaf = true; // 如果不含实例则为空节点 if (Utils.eq(sumOfWeights, 0)) m_isEmpty = true; } }

WEKA算法解析 -- PART决策树相关推荐

  1. WEKA算法开发——记一次不太成功的遗传属性加权贝叶斯算法实验

    WEKA算法开发--记一次不太成功的遗传属性加权贝叶斯算法实验 1. WEKA介绍 2. 使用WEKA开发自己的算法 3. ~~总结~~ 吐槽 1. WEKA介绍 Weka平台是一种数据分析+模式识别 ...

  2. 回归算法分类,常用回归算法解析

    回归算法分类,常用回归算法解析 回归是数学建模.分类和预测中最古老但功能非常强大的工具之一.回归在工程.物理学.生物学.金融.社会科学等各个领域都有应用,是数据科学家常用的基本工具. 回归通常是机器学 ...

  3. CVPR目标检测与实例分割算法解析:FCOS(2019),Mask R-CNN(2019),PolarMask(2020)

    CVPR目标检测与实例分割算法解析:FCOS(2019),Mask R-CNN(2019),PolarMask(2020) 目标检测:FCOS(CVPR 2019) 目标检测算法FCOS(FCOS: ...

  4. 10没有基于策略的qos_分布式QoS算法解析

    QoS对于服务多租户多业务的整体系统来说,不管对网络还是存储,都格外重要,没有QoS,会造成不同租户及业务之间对资源的抢占,用户A用爽了,用户B却遭了殃,频频投诉,这是系统管理员最头疼的事情.我们今天 ...

  5. python终结一个循环额_Python语言入门之内存管理方式和垃圾回收算法解析

    本文主要向大家介绍了Python语言入门之内存管理方式和垃圾回收算法解析,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助. 在列表,元组,实例,类,字典和函数中存在循环引用问题.有 ...

  6. 脑机接口主流算法解析课程视频汇总

    目录 讲座1--SSVEP算法解析 讲座2--ERP/P300算法解析 讲座3--运动想象算法解析 讲座4--情感脑机接口算法解析 本分享为脑机学习者Rose整理发表于公众号:脑机接口社区 .QQ交流 ...

  7. yolo类检测算法解析——yolo v3

    原文:https://www.cnblogs.com/cvtoEyes/p/8608205.html yolo类检测算法解析--yolo v3 计算机视觉的发展史可谓很长了,它的分支很多,而且理论那是 ...

  8. 【机器学习】通俗的元胞自动机算法解析和应用

    [机器学习]通俗的元胞自动机算法解析和应用 文章目录 1 元胞自动机的定义 2 元胞自动机的组成 3 元胞自动机的特征 4 Python实现元胞自动机(生命游戏) 5 总结 6 Github(华盛顿州 ...

  9. 【机器学习】树回归和聚类算法解析和应用

    [机器学习]树回归和聚类算法解析和应用 文章目录 1 树回归 2 CART ( Classification And Regression Tree) 分类回归树 3 K-means3.1 合理选择 ...

最新文章

  1. 吴恩达神经网络和深度学习——第三周笔记
  2. 2020 我的C++的学习之路
  3. LVM---逻辑盘卷管理
  4. 清华博士生放弃科研,跑去当中学教师,值得吗?
  5. 你的代码是否按照高内聚、低耦合的原则来设计的?
  6. 【JavaScript】编写一个炫彩的网页时钟
  7. Netty的核心组件
  8. vim 批量替换字符串_Vim 有什么奇技淫巧?
  9. 揭秘富人见不得光的第一桶金都是怎么来的
  10. copy 浅复制 与深复制
  11. 毕设题目:Matlab指纹识别
  12. 晶振为什么不封装进芯片内部?
  13. 嵌入式控制K60考试复习
  14. 蒙特卡洛模拟 matlab实例,蒙特卡洛模拟的简单例子
  15. inverted dropout(反向随机失活)正则化
  16. 支付宝SDK下载地址
  17. tsmc 7nm工艺下用做syncCell的stdCell介绍
  18. oracle_odac安装,Hello World - Viasual Studio + Oracle (ODAC / ODT) 开发环境配置注意事项
  19. 如何在内存中执行二进制代码之win平台
  20. 三水维修松下服务器,松下A6驱动器佛山维修

热门文章

  1. 3D MAX模型导入Revi
  2. python怎么安装bokeh_Python如何使用bokeh包和geojson数据绘制地图
  3. 沁恒触摸蓝牙模块方案测试体验(CH582)
  4. 中国SaaS的机遇、战术和野心
  5. Element tree树组件 鼠标双击事件
  6. 《上海交通大学学生生存手册》读书笔记
  7. 全新自适应地址发布页HTML源码
  8. Set集合下的奇葩,TreeSet有序而且类型相同
  9. 小米手机系统脚本上传服务器文件夹,小米手机与电脑可以高速传文件?看看这些你也许会明白-红米手机怎么连接电脑...
  10. 关于国信证券的丑恶现象