决策树简介及用python实现

来源:互联网 发布:执业药师注册网络平台 编辑:程序博客网 时间:2024/05/15 08:08

一、决策树简介


决策树算法是一种逼近离散函数值的方法。它是一种典型的分类方法,首先对数据进行处理,利用归纳算法生成可读的规则和决策树,然后使用决策对新数据进行分析。本质上决策树是通过一系列规则对数据进行分类的过程。


1、决策树引导


一个女孩找对象策过程就是型的分类树决策。相当于通过年龄、长相、收入和是否公务员对将男人分为两个类别:见和不见。假设这个女孩对男

人的要求是:30岁以下、长相中等以上并且是高收入者或中等以上收入的公务员,那么这个可以用下图表示女孩的决策逻辑:

  

上图完整表达了这个女孩决定是否见一个约会对象的策略,其中绿色节点表示判断条件,橙色节点表示决策结果,箭头表示在一个判断条件在不同情况下的决策路径,图中红色箭头表示了上面例子中女孩的决策过程。

      这幅图基本可以算是一颗决策树,说它“基本可以算”是因为图中的判定条件没有量化,如收入高中低等等,还不能算是严格意义上的决策树,如果将所有条件量化,则就变成真正的决策树了。

      有了上面直观的认识,我们可以正式定义决策树了:

     决策树(decision tree)是一个树结构(可以是二叉树或非二叉树)。其每个非叶节点表示一个特征属性上的测试,每个分支代表这个特征属性在某个值域上的输出,而每个叶节点存放一个类别。使用决策树进行决策的过程就是从根节点开始,测试待分类项中相应的特征属性,并按照其值选择输出分支,直到到达叶子节点,将叶子节点存放的类别作为决策结果。

      可以看到,决策树的决策过程非常直观,容易被人理解。目前决策树已经成功运用于医学、制造产业、天文学、分支生物学以及商业等诸多领域。


2、决策树构造


构造决策树的关键步骤是分裂属性。所谓分裂属性就是在某个节点处按照某一特征属性的不同划分构造不同的分支,其目标是让各个分裂子集尽可能地“纯”。尽可能“纯”就是尽量让一个分裂子集中待分类项属于同一类别。分裂属性分为三种不同的情况:

     (1)属性是离散值且不要求生成二叉决策树。此时用属性的每一个划分作为一个分支。

      (2)属性是离散值且要求生成二叉决策树。此时使用属性划分的一个子集进行测试,按照“属于此子集”和“不属于此子集”分成两个分支。

      (3)属性是连续值。此时确定一个值作为分裂点split_point,按照>split_point和<=split_point生成两个分支。


算法:ID3算法


从信息论知识中我们直到,期望信息越小,信息增益越大,从而纯度越高。所以ID3算法的核心思想就是以信息增益度量属性选择,选择分裂后信息增益最大的属性进行分裂。下面先定义几个要用到的概念。

设X为用类别对训练元组进行的划分,则X的(entropy)表示为:

                              

其中pi表示第i个类别在整个训练元组中出现的概率,可以用属于此类别元素的数量除以训练元组元素总数量作为估计。

条件熵:它度量了我们的X在知道Y以后剩下的不确定性。表达式为:

                     

信息增益是特征选择中的一个重要指标,它定义为一个特征能够为分类系统带来多少信息,带来的信息越多,该特征越重要。

表达式为:

                 H(X)-H(X|Y)                                                                       

具体操作:

1)树以代表训练样本的单个结点开始。

2)如果样本都在同一个类.则该结点成为树叶,并用该类标记。

3)否则,算法选择最有分类能力的属性作为决策树的当前结点.

4)根据当前决策结点属性取值的不同,将训练样本数据集tlI分为若干子集,每个取值形成一个分枝,有几个取值形成几个分枝。匀针对上一步得到的一个子集,重复进行先前步骤,递4'I形成每个划分样本上的决策树。一旦一个属性出现在一个结点上,就不必在该结点的任何后代考虑它。

5)递归划分步骤仅当下列条件之一成立时停止:

①给定结点的所有样本属于同一类。

②没有剩余属性可以用来进一步划分样本.在这种情况下.使用多数表决,将给定的结点转换成树叶,并以样本中元组个数最多的类别作为类别标记,同时也可以存放该结点样木的类别分布,

③如果某一分支没有样本,则以样本的多数类创建一个树叶。


二、python代码的实现:


代码:

from math import logimport operatordataSet = [[1,1,0,'fight'],[1,0,1,'fight'],[1,0,1,'fight'],               [1,0,1,'fight'],[0,0,1,'run'],[0,1,0,'fight'],               [0,1,1,'run']]                         #需处理的数据labels = ['weapon','bullet','blood']          #对应的标签def calcShannonEnt(dataSet):    numEntries = len(dataSet)    lableCounts = {}    for featVec in dataSet:        currentLable = featVec[-1]         #取数据中各元素的最后一项:类别        if currentLable not in lableCounts.keys():            lableCounts[currentLable] = 0        lableCounts[currentLable] += 1      #给类别计数    shannonEnt = 0    for key in lableCounts:        prob = float(lableCounts[key])/numEntries        shannonEnt -= prob * log(prob,2)          #计算熵的值    return shannonEnt                            #返回熵的值def splitDataSet(dataSet,axis,value):    retDataSet = []                                    #创建新列表retDataSet     for featVec in dataSet:        if featVec[axis] == value:            reducedFeatVec = featVec[:axis]            reducedFeatVec.extend(featVec[axis+1:])            retDataSet.append(reducedFeatVec)    return retDataSetdef chooseBestFeatureToSplit(dataSet):    numFeatures = len(dataSet[0]) - 1         #减去最后一项(类别)    baseEntropy = calcShannonEnt(dataSet)    bestInfoGain = 0.0    bestFeature = -1    for i in range(numFeatures):        featList = [example[i] for example in dataSet]        uniqueVals = set(featList)        newEntropy = 0.0        for value in uniqueVals:            subDataSet = splitDataSet(dataSet, i, value)              #调用splitDataSet函数            prob = len(subDataSet) / float(len(dataSet))            newEntropy += prob * calcShannonEnt(subDataSet)         #计算条件熵的值            infoGain = baseEntropy -newEntropy            #计算信息增益的值        if infoGain > bestInfoGain:            bestInfoGain = infoGain            bestFeature = i                  #比较信息增益    return bestFeature                  #返回信息增益最大的位置'''因为我们递归构建决策树是根据属性的消耗进行计算的,所以可能会存在最后属性用完了,但是分类还是没有算完,这时候就会采用多数表决的方式计算节点分类'''def majorityCnt(classList):    classCount = {}    for vote in classList:        if vote not in classCount.keys():            classCount[vote] = 0        classCount[vote] += 1    return max(classCount)                   #返回多数表决后的结果def createTree(dataSet, labels):    classList = [example[-1] for example in dataSet]    if classList.count(classList[0]) ==len(classList):        return classList[0]                         #所有类别都相同则停止划分,直接返回该类别    if len(dataSet[0]) == 1:                    #所有特征已经用完        return majorityCnt(classList)          #返回多数表决后的结果    bestFeat = chooseBestFeatureToSplit(dataSet)              #调用chooseBestFeatureToSplit函数    bestFeatLabel = labels[bestFeat]    myTree = {bestFeatLabel:{}}    del(labels[bestFeat])                             #删除信息增益最大的位置对应的标签    featValues = [example[bestFeat] for example in dataSet]    uniqueVals = set(featValues)    for value in uniqueVals:        subLabels = labels[:]             #为了不改变原始列表的内容复制了一下        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)    return myTreemyTree = createTree(dataSet,labels)print myTree


输出结果为:

{'weapon': {0: {'blood': {0: 'fight', 1: 'run'}}, 1: 'fight'}}


三、小结

在实际构造决策树时,通常要进行剪枝,这时为了处理由于数据中的噪声和离群点导致的过分拟合问题。剪枝有两种:

      先剪枝——在构造过程中,当某个节点满足剪枝条件,则直接停止此分支的构造。

      后剪枝——先构造完成完整的决策树,再通过某些条件遍历树进行剪枝


决策树算法的优点如下:

(1)分类精度高;

(2)生成的模式简单;

(3)对噪声数据有很好的健壮性。

因而是目前应用最为广泛的归纳推理算法之一,在数据挖掘中受到研究者的广泛关注。


原创粉丝点击