决策树和随机森林

1、前述html

决策树是一种非线性有监督分类模型,随机森林是一种非线性有监督分类模型。线性分类模型好比说逻辑回归,可能会存在不可分问题,可是非线性分类就不存在。
2、具体原理node

ID3算法算法

一、相关术语apache

根节点:最顶层的分类条件
叶节点:表明每个类别号
中间节点:中间分类条件
分枝:表明每个条件的输出
二叉树:每个节点上有两个分枝
多叉树:每个节点上至少有两个分枝dom

 二、决策树的生成:机器学习

数据不断分裂的递归过程,每一次分裂,尽量让类别同样的数据在树的一边,当树的叶子节点的数据都是一类的时候,则中止分类。(if else 语句)函数

三、如何衡量纯粹度

举例:学习

箱子1:100个红球
箱子2:50个红球  50个黑球
箱子3:10个红球  30个蓝球 60绿球
箱子4:各个颜色均10个球测试

凭人的直觉感觉,箱子1是最纯粹的,箱子4是最混乱的,如何把人的直觉感觉进行量化呢?
将这种纯粹度用数据进行量化,计算机才能读懂spa

举例:

度量信息混乱程度指标:

熵的介绍:

熵公式举例:

熵表明不肯定性,不肯定性越大,熵越大。表明内部的混乱程度。

好比两个集合  A有5个类别 每一个类别2个值 则每一个几率是0.2

好比B有两个类别,每一个类别5个 ,则每一个几率是0.5

显然0.5大于0.2因此熵大,混乱程度比较大。


信息熵H(X):信息熵是香农在1948年提出来量化信息的信息量的。熵的定义以下

n表明种类,每个类别中,p1表明某个种类的几率*log当前种类的几率,而后将各个类别计算结果累加。

以上例子车祸的信息熵是-(4/9log4/9+5/9log5/9)

条件熵:H(X,Y)相似于条件几率,在知道X的状况下,Y的不肯定性

以上例子在知道温度的状况下,求车祸的几率。

hot 是3个,其中两个没有车祸,一个车祸,则3/9(2/3log2/3+1/3log1/3)。

mild是2个,其中一个车祸,一个没有车祸,则2/9(1/2log1/2+1/2log1/2)

cool是4个,其中三个车祸,一个没有车祸,则4/9(3/4log3/4+1/4log1/4)。

以上相加即为已知温度的状况下,车祸的条件熵。

信息增益:表明的熵的变化程度
                 特征Y对训练集D的信息增益g(D,Y)= H(X) - H(X,Y)
以上车祸的信息熵-已知温度的条件熵就是信息增益。

信息增益便是表示特征X使得类Y的不肯定性减小的程度。
(分类后的专注性,但愿分类后的结果是同类在一块儿)

信息增益越大,熵的变化程度越大,分的越干脆,越完全。不肯定性越小。

在构建决策树的时候就是选择信息增益最大的属性做为分裂条件(ID3),使得在每一个非叶子节点上进行测试时,都能得到最大的类别分类增益,使分类后数据集的熵最小,这样的处理方法使得树的平均深度较小,从而有效提升了分类效率。

 

C4.5算法:有时候给个特征,它分的特别多,可是彻底分对了,好比训练集里面的编号
信息增益特别大,都甚至等于根节点了,那确定是不合适的
问题在于行编号的分类数目太多了,分类太多意味着这个特征自己的熵大,大到都快是整个H(X)了
为了不这种现象的发生,咱们不是用信息增益自己,而是用信息增益除以这个特征自己的熵值,看除以后的值有多大!这就是信息增益率,若是用信息增益率就是C4.5

 

CART算法:

CART使用的是GINI系数相比ID3和C4.5,CART应用要多一些,既能够用于分类也能够用于回归。

CART假设决策树是二叉树,内部结点特征的取值为“是”和“否”,左分支是取值为“是”的分支,右分支是取值为“否”的分支。这样的决策树等价于递归地二分每一个特征,将输入空间即特征空间划分为有限个单元,并在这些单元上肯定预测的几率分布,也就是在输入给定的条件下输出的条件几率分布。

CART算法由如下两步组成:

  1. 决策树生成:基于训练数据集生成决策树,生成的决策树要尽可能大;
  2. 决策树剪枝:用验证数据集对已生成的树进行剪枝并选择最优子树,这时损失函数最小做为剪枝的标准。

CART决策树的生成就是递归地构建二叉决策树的过程。CART决策树既能够用于分类也能够用于回归。本文咱们仅讨论用于分类的CART。对分类树而言,CART用Gini系数最小化准则来进行特征选择,生成二叉树。GINI系数实际上是用直线段代替曲线段的近似,GINI系数就是熵的一阶近似。

公式以下:

好比两个集合  A有5个类别 每一个类别2个值 则每一个几率是0.2

好比B有两个类别,每一个类别5个 ,则每一个几率是0.5

假设C有一个类别,则基尼系数是0 ,类别越多,基尼系数越接近于1,因此

咱们但愿基尼系数越小越好

CART生成算法以下:

输入:训练数据集中止计算的条件: 
输出:CART决策树。

过程:

损失函数:

以上构建好分类树以后,评价函数以下:

(但愿它越小越好,相似损失函数了)

3、解决过拟合问题方法

 一、背景

叶子节点的个数做为加权叶子节点的熵乘以加权的加和就是评价函数这就是损失函数,这个损失函数确定是越小越好了

如何评价呢?
用训练数据来计算损失函数,决策树不断生长的时候,看看测试数据损失函数是否是变得越低了,
这就是交互式的作调参的工做,由于咱们可能须要作一些决策树叶子节点的剪枝,由于并非树越高越好,由于树若是很是高的话,可能过拟合了。

二、解决过拟合两种方法

剪枝

随机森林

三、解决过拟合方法之剪枝

为何要剪枝:决策树过拟合风险很大,理论上能够彻底分得开数据(想象一下,若是树足够庞大,每一个叶子节点不就一个数据了嘛)
剪枝策略:预剪枝,后剪枝
预剪枝:边创建决策树边进行剪枝的操做(更实用)
后剪枝:当创建完决策树后来进行剪枝操做

预剪枝(用的多)
边生成树的时候边剪枝,限制深度,叶子节点个数,叶子节点样本数,信息增益量等树的高度,每一个叶节点包含的样本最小个数,每一个叶节点分裂的时候包含样本最小的个数,每一个叶节点最小的熵值等max_depth min_sample_split min_sample_leaf min_weight_fraction_leaf,max_leaf_nodes max_features,增长min_超参 减少max_超参
后剪枝

叶子节点个数越多,损失越大
仍是生成一颗树后再去剪枝,alpha值给定就行

后剪枝举例:

四、解决过拟合方法之随机森林

思想Bagging的策略:

从样本集中重采样(有可能存在重复)选出n个样本在全部属性上,对这n个样本创建分类器(ID三、C4.五、CART、SVM、Logistic回归等)
重复上面两步m次,产生m个分类器将待预测数据放到这m个分类器上,最后根据这m个分类器的投票结果,决定待预测数据属于那一类(即少数服从多数的策略)

在Bagging策略的基础上进行修改后的一种算法
从样本集中用Bootstrap采样选出n个样本;
从全部属性中随机选择K个属性,选择出最佳分割属性做为节点建立决策树;
重复以上两步m次,即创建m棵CART决策树;
这m个CART造成随机森林(样本随机,属性随机),经过投票表决结果决定数据属于那一类。

当数据集很大的时候,咱们随机选取数据集的一部分,生成一棵树,重复上述过程,咱们能够生成一堆形态万千的树,这些树放在一块儿就叫森林。

随机森林之因此随机是由于两方面:样本随机+属性随机

选取过程:

取某些特征的全部行做为每个树的输入数据。

而后把测试数据带入到每个数中计算结果,少数服从多数,便可求出最终分类。

随机森林的思考:

在随机森林的构建过程当中,因为各棵树之间是没有关系的,相对独立的;在构建
的过程当中,构建第m棵子树的时候,不会考虑前面的m-1棵树。所以引出提高的算法,对分错的样本加权。

提高是一种机器学习技术,能够用于回归和分类的问题,它每一步产生弱预测模型(如决策树),并加权累加到总模型中;若是每一步的弱预测模型的生成都是依
据损失函数的梯度方式的,那么就称为梯度提高(Gradient boosting)提高技术的意义:若是一个问题存在弱预测模型,那么能够经过提高技术的办法获得一个强预测模型。

4、代码

决策树:

决策树的训练集必须离散化,由于若是不离散化的话,分类节点不少。

package com.bjsxt.rf
 
import org.apache.spark.mllib.tree.DecisionTree
import org.apache.spark.mllib.util.MLUtils
import org.apache.spark.{SparkContext, SparkConf}
 
object ClassificationDecisionTree {
  val conf = new SparkConf()
  conf.setAppName("analysItem")
  conf.setMaster("local[3]")
  val sc = new SparkContext(conf)
 
  def main(args: Array[String]): Unit = {
    val data = MLUtils.loadLibSVMFile(sc, "汽车数据样本.txt")
    // Split the data into training and test sets (30% held out for testing)
    val splits = data.randomSplit(Array(0.7, 0.3))
    val (trainingData, testData) = (splits(0), splits(1))
    //指明类别
    val numClasses=2
    //指定离散变量,未指明的都看成连续变量处理
    //1,2,3,4维度进来就变成了0,1,2,3
    //这里天气维度有3类,可是要指明4,这里是个坑,后面以此类推
    val categoricalFeaturesInfo=Map[Int,Int](0->4,1->4,2->3,3->3)
    //设定评判标准
    val impurity="entropy"
    //树的最大深度,太深运算量大也没有必要  剪枝   防止模型的过拟合!!!
    val maxDepth=3
    //设置离散化程度,连续数据须要离散化,分红32个区间,默认其实就是32,分割的区间保证数量差很少 这里能够实现把数据分到0-31这些数中去  这个参数也能够进行剪枝
    val maxBins=32
    //生成模型
    val model =DecisionTree.trainClassifier(trainingData,numClasses,categoricalFeaturesInfo,impurity,maxDepth,maxBins)
   //测试
   val labelAndPreds = testData.map { point =>
     val prediction = model.predict(point.features)
     (point.label, prediction)
   }
    val testErr = labelAndPreds.filter(r => r._1 != r._2).count().toDouble / testData.count()//错误率的统计
    println("Test Error = " + testErr)
    println("Learned classification tree model:\n" + model.toDebugString)
 
     }
}

样本数据:

将第5列数据离散化。

结果:

深度为3一共15个节点。

随机森林:

package com.bjsxt.rf
 
import org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.mllib.util.MLUtils
import org.apache.spark.mllib.tree.RandomForest
 
object ClassificationRandomForest {
  val conf = new SparkConf()
  conf.setAppName("analysItem")
  conf.setMaster("local[3]")
  val sc = new SparkContext(conf)
  def main(args: Array[String]): Unit = {
    //读取数据
    val data =  MLUtils.loadLibSVMFile(sc,"汽车数据样本.txt")
    //将样本按7:3的比例分红
    val splits = data.randomSplit(Array(0.7, 0.3))
    val (trainingData, testData) = (splits(0), splits(1))
    //分类数
    val numClasses = 2
    // categoricalFeaturesInfo 为空,意味着全部的特征为连续型变量
    val categoricalFeaturesInfo =Map[Int, Int](0->4,1->4,2->3,3->3)
    //树的个数
    val numTrees = 3
    //特征子集采样策略,auto 表示算法自主选取
    //"auto"根据特征数量在4个中进行选择
    // 1,all 所有特征 2,sqrt 把特征数量开根号后随机选择的 3,log2 取对数个 4,onethird 三分之一
    val featureSubsetStrategy = "auto"
    //纯度计算
    val impurity = "entropy"
    //树的最大层次
    val maxDepth = 3
    //特征最大装箱数,即连续数据离散化的区间
    val maxBins = 32
    //训练随机森林分类器,trainClassifier 返回的是 RandomForestModel 对象
    val model = RandomForest.trainClassifier(trainingData, numClasses, categoricalFeaturesInfo,
      numTrees, featureSubsetStrategy, impurity, maxDepth, maxBins)
    //打印模型
    println(model.toDebugString)
    //保存模型
   //model.save(sc,"汽车保险")
    //在测试集上进行测试
    val count = testData.map { point =>
    val prediction = model.predict(point.features)
//    Math.abs(prediction-point.label)
    (prediction,point.label)
     }.filter(r => r._1 != r._2).count()
    println("Test Error = " + count.toDouble/testData.count().toDouble)
  }
}

结果:

根据DEBUGTREE画图举例:

原贴:http://www.javashuo.com/article/p-crzpfvuv-u.html

相关文章
相关标签/搜索