决策树之构造决策树(一)

     决策树时一种常用的数据挖掘算法,其优势在于数据形式非常容易理解,缺点在于很可能产生过度匹配的问题(即过拟合问题,如何解决过拟合问题待续.......)。决策树的一个重要任务就是为了理解数据中所蕴含的数据信息,因此决策树可以使用不熟悉的数据集合,并从中提取出一系列的规则,这些机器根据数据集创建规则的过程,就是机器学习的过程。决策树给出的结果往往可以匹敌在当前领域具有几十年工作经验的人类专家。

    构造决策树:

面临的第一个问题:当前数据集上哪个特征在划分数据分类时起到决定性作用??为了找到决定性的特征,划分出最好的结果,我们需要对每个特征进行评估。创建决策树步骤大致如下:

  1.     寻找数据集中最好的特征
  2.     根据最好的特征划分数据集
  3.     再到划分好的数据集中去寻找这个子数据集中最好的特征,就是重复1,2步,直到检测到数据集中每个子项属于同一分类,或遍历完所有的特征,循环结束。创建分支函数createBranch()的伪代码如下:

     检测数据集中的每个子项是否属于同一分类:

              If so return 类标签

              Else 

                      寻找到划分数据集的最好特征

                      根据这个最好特征划分数据集

                      创建分支节点

                                    for 每个划分的子集

                                          调用函数createBranch并增加返回结果到分支节点中

                        return  分支节点                          


那么问题又来了,在一个数据集中,我们怎么找到一个最好特征来划分数据集呢??用什么衡量一个特征的好坏??划分数据的原则就是,将无序的数据变得更加有序。划分数据集的方法有多种,本文是通过信息增益(信息论知识)来衡量。信息增益是指数据集在划分之前之后的信息变化。信息熵通常用来度量集合信息。熵定义为信息的期望值。

信息计算公式如下:

                                           l(x_{i}) = - log_{2}p(x_{i})                                             其中p(x_{i})x_{i}发生的概率

熵的计算公式如下:

                                        H = -\sum_{1}^{n}p(x_{i})log_{2}p(x_{i})

计算数据集信息熵的python代码实现如下:

from math import log
import operator
# 求数据集的信息熵,熵越大,说明不确定性就越高,说明类别就越多
def calcShannonEnt(dataSet):
    numEntrise = len(dataSet)
    labelCounts = {}
    for featVec in dataSet:
        if len(featVec) > 0 :
            currentLabel = featVec[-1]
            if currentLabel not in labelCounts.keys():
                labelCounts[currentLabel] = 0
            labelCounts[currentLabel] += 1
    shannonEnt = 0.0
    for key in labelCounts:
        prob = float(labelCounts[key])/numEntrise  # 求概率
        shannonEnt -= prob * log(prob,2) #求熵
    return shannonEnt

创建测试数据集可以用如下代码:

# 创建数据集
def createDataSet():
    dataSet = [[1,1,'yes'],
        [1,1,'yes'],
        [1, 0, 'no'],
        [0, 1, 'no'],
        [0,1,'no']]
    labels = ['no surfacing','flippers']
    return dataSet ,labels

数据集的信息熵我们知道怎么求了,那么如何每个特征的信息增益呢?(信息增益最大的那个特征则是数据集中最好的那个特征,我们就可以根据这个特征去划分数据集了)信息增益是数据集划分前后的一个信息熵的变化差值,所以数据集被每个特征划分前数据集的信息熵和划分后的数据集的信息熵。那么我们有面临一个问题,如何根据特征来划分数据据呢??具体代码如下:

# 按照给定特征划分数据集
'''
dataSet:待划分的数据集
axis:划分数据集的特征
value:需要返回的特征的值(一个值对应一个数据集)
'''
def splitDataSet(dataSet,axis,value):
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet

现在可以根据特征和需要返回的特征值来划分数据集了,接下来需要求的就是每个特征划分数据集时的信息增益了,信息增益最大的那个特征,就是最好划分数据集的特征,具体代码实现如下:

# 选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0])-1 # 获取特征的个数
    baseEntropy = calcShannonEnt(dataSet)  # 数据集的信息熵
    bastInfoGain = 0.0 ; bastFeature = -1 ;
    for i in range(numFeatures):
        featList = [example[i] for example in dataSet]  # 获取数据集中的某列
        uniqueVals = set(featList) # 转为set集合,达到去重效果
        newEntropy = 0.0
        for value in uniqueVals:
            subDataSet = splitDataSet(dataSet,i,value)
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob*calcShannonEnt(subDataSet)
        infoGain = baseEntropy - newEntropy     # 信息增益
        if(infoGain > bastInfoGain):           #求最好特征逻辑
            bastInfoGain = infoGain          
            bastFeature = i
    return bastFeature

现在求最好特征已经实现了,那么就可以开始递归构建决策树了。工作原理如下:获取原始数据集,然后基于最好的特征去划分数据集,由于特征值可能多于两个,因此可能存在两个分支的数据集划分。第一次划分之后,数据将被向下传递到树分支的下一个节点上,我们可以再次划分数据集,所以可以采用递归的思想。递归结束的条件有两个:1.程序遍历完所有的划分数据集的特征 2.每个分支下所有的实例都具有相同的分类。

构造决策树还有其他算法,如C4.5和CART,待后续研究....

当前算法任然存在问题,如:当所有的特征都遍历完了,类标签(特征值)仍然不唯一,此时应该如何定义这叶子节点呢?通常这种情况我们采用多数表决法,即少数服从多数的方法。具体代码实现如下:

# 多数表决法决定叶子节点的分类
def majorityCnt(classList):
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] +=1
    sortedClassCount = sorted(classCount.__iter__(),key=operator.itemgetter(1),reverse=True)
    return  sortedClassCount[0][0]

接下来就是激动人心的时刻了,决策树构造。具体代码实现如下:

#创建树的函数代码
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)           #求划分数据集的最好的特征
    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 myTree

最终构造决策树如下:

       ps:哈哈哈,表述出来不容易啊,对决策树理解更清晰了。机器学习新手上路,老司机们多多关照,后续还有更新哦~~~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值