4.1 决策树算法简介

决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。决策树是一种基于树结构的监督学习模型,用于分类和回归任务。其核心原理是通过递归地选择最优特征进行数据划分,构建树形结构以进行预测。

决策树易于理解和实现,不需要初学者具有很深的背景知识,生成的决策树所表达的意义易于解释。可以通过每个特征的信息增益来评估每个特征对决策树模型的贡献度。决策树对数据有较强的适应性,它既能处理数值型数据也可以处理逻辑型数据。生成决策树的时间相对较短且决策树模型的分类效果良好。

对于大规模数据集,决策树的训练时间可能显著增加,尤其是当特征维度较高时。决策树对连续性的字段比较难预测,以及对有时间顺序的数据,需要很多预处理的工作。决策树的性能高度依赖于参数设置(如最大深度、最小样本分裂数等),其调参过程较为复杂。

4.2 算法的基本原理

决策树作为一种在机器学习领域内极具代表性的算法,其核心设计理念在于巧妙地模仿人类在面对复杂问题时所运用的决策过程。在现实生活的诸多场景中,人类往往会将一个庞大且复杂的难题逐步拆解为一系列相对简单、易于判断的小问题,通过逐层分析这些小问题,最终得出对整体问题的解决方案。决策树正是借鉴了这种思维方式,它将复杂问题精心分解为多层简单判断,每一层判断都如同人类决策过程中的一个关键节点,通过不断地对这些节点进行评估和选择,逐步引导我们走向最终的决策结果。

(1)信息熵

熵定义为信息的期望值,在信息论与概率统计中,熵是表示随机变量不确定性的度量,用一句通俗的话讲就是这个体系的混乱程度是如何的。假设有一个样本数为n的数据集,第i类样本为xi,其中p(xi)是选择该分类的概率。通过改变i的值即可获得数据集中所有类别的信息。那么xi变量的信息可由式(1)计算。为了计算熵,我们需要计算所有类别所有可能值包含的信息期望值(数学期望),通过下面的公式(2)求得。

L(xi)=-log2p(xi)                                  1

H=-i=1npxilog2pxi                                                             2)

(2)信息增益

不论一个数据集有多少特征,每次划分数据集时只能选一个特征,那么第一次选择哪个特征作为划分的参考特征呢?答案一定是分类能力最好的那个特征。但问题来了,如何判断哪一个特征分类能力最好呢?这时就要引入一个新的概念——信息增益。什么是信息增益呢?在划分数据集之前和之后信息发生的变化称为信息增益,知道如何计算信息增益,我们就可以计算每个特征值划分数据集获得的信息增益,获得信息增益最高的特征就是最好的选择。信息增益可由公式(3)求得。E(D)是划分之前数据集D的熵(即数据集中目标变量Y的不确定性)。E(DX)是在特征X的条件下,划分后的数据集的加权平均熵,表示划分后的数据集的剩余不确定性。

IG(D,X)=E(D)-E(D|X)                                                                 (3)

(3)决策树模型的构建

决策树模型的构建过程是一个不断地选择最优特征,并根据最优特征对训练数据进行划分的过程,从而将各个子数据集划分到最合适的类别。综上所述,为了系统地构建决策树模型,整个过程大致可以划分为特征选择、数据集划分与类别归属三个核心步骤,每一步都紧密相连,共同推动着决策树的生长与完善。

a.从所有特征中选一个最优特征,作为根节点。这一最优特征将训练数据集分割成若干子集,使得各个子集有一个在当前特征条件下具有最好的分类。

b.如果还有特征没有使用,那么就对这些子集选择新的最优特征,继续对其进行划分,生成枝节点,直至所有特征用完为止。

c.此时,每个子集都被分到叶子节点上,即都有了明确的类别,这样就生成了一棵决策树。

(4)基于信息增益的最优特征选择

1fish为例,在no surfacing中,1代表不浮出水面可以生存,0代表不浮出水面不可以生存。在flippers中,1代表有脚蹼,0代表没有脚蹼。在fish中,yes代表是鱼类,no代表不是鱼类。

1 判断是不是鱼类

No.

no surfacing

flippers

fish

1

1

1

yes

2

1

1

yes

3

1

0

no

4

0

1

no

5

0

1

no

"no surfacing"这一特征,5个样本中的"1"3个,"0"2个,所以"1"的权重为3/5"0"的权重为2/5。对于"1"的三个样本,fish"yes"有两个,"no"有一个,所以分类的概率分别为2/31/3。对于"0"的两个样本,fish都为"no",所以分类概率为2/2。信息增益G的计算过程如下。

"flippers"这一特征,5个样本中的"1"4个,"0"1个,所以"1"的权重为4/5"0"的权重为1/5。对于"1"的四个样本,fish"yes"有两个,"no"有两个,所以分类的概率分别为2/42/4。对于"0"的一个样本,fish"no",所以分类概率为1/1。信息增益G的计算过程如下。

G(no surfacing”)=0.4199730940219749

G(flippers”)=0.1709505944546686

因为G(no surfacing)>G(flippers),所以“no surfacing”是最优特征。

4.3 算法实例

以表1为训练和测试数据,基于决策树算法实现分类。其实例操作过程如下:1.收集数据:可以使用任何方法。2.导入相关库和数据集。3.计算给定数据集的香农熵。4.测试熵的变化。5.按照给定特征划分数据集。6.选择最好的数据集划分方式。7.递归构建决策树。

  1. 收集数据

可以灵活运用多种方法,例如通过专业数据库检索、实地采样调查、公开数据集下载等,以确保数据的全面性与代表性。本实验以海洋生物的数据(表1)为训练和测试数据,基于决策树算法实现分类。相关数据上文可查看上文。

  1. 导入相关库和数据集

createDataSet()函数,其功能是生成一个简单的示例数据集和对应的特征标签,主要用于演示决策树算法的基本操作(如信息熵计算、特征划分等)。

相关代码如下:

def createDataSet():

    dataSet = [[1, 1, 'yes'],

               [1, 1, 'yes'],

               [1, 0, 'no'],

               [0, 1, 'no'],

               [0, 1, 'no']]

    labels = ['no surfacing', 'flippers']

    # change to discrete values

return dataSet, labels

1 数据载入

  1. 计算给定数据集的香农熵

calcShannonEnt(dataSet)函数,其功能是计算给定数据集的信息熵(香农熵),用于衡量数据的混乱程度或不确定性。信息熵是决策树算法(如ID3)中用于特征选择的关键指标。

相关代码如下:

def calcShannonEnt(dataSet):

    numEntries = len(dataSet)

    labelCounts = {}

    for featVec in dataSet:  # the the number of unique elements and their occurance

        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]) / numEntries

        shannonEnt -= prob * log(prob, 2)  # log base 2

return shannonEnt

2 计算给定数据集的香农熵

  1. 测试熵的变化

calcShannonEnt(dataSet)函数,用于计算数据集的信息熵(香农熵)。信息熵是信息论中的核心概念,在决策树算法中用于衡量数据的混乱程度或不确定性。

相关代码如下:

def calcShannonEnt(dataSet):

    numEntries = len(dataSet)

    labelCounts = {}

    for featVec in dataSet:  # the the number of unique elements and their occurance

        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]) / numEntries

        shannonEnt -= prob * log(prob, 2)  # log base 2

return shannonEnt

3 测试熵的变化

  1. 按照给定特征划分数据集

splitDataSet(dataSet, axis, value)函数,其功能是根据给定特征和特征值对数据集进行划分,返回符合条件的子数据集。这是决策树算法中用于递归划分数据的关键步骤。

相关代码如下:

def splitDataSet(dataSet, axis, value):

    retDataSet = []

    for featVec in dataSet:

        if featVec[axis] == value:

            reducedFeatVec = featVec[:axis]  # chop out axis used for splitting

            reducedFeatVec.extend(featVec[axis + 1:])

            retDataSet.append(reducedFeatVec)

return retDataSet

4 划分数据集

  1. 选择最好的数据集划分方式

chooseBestFeatureToSplit(dataSet)函数,其功能是根据信息增益选择最优划分特征,这是决策树算法(如ID3)中决定如何分裂节点的核心步骤。

相关代码如下:

def chooseBestFeatureToSplit(dataSet):

    numFeatures = len(dataSet[0]) - 1  # the last column is used for the labels

    baseEntropy = calcShannonEnt(dataSet)

    bestInfoGain = 0.0;

    bestFeature = -1

    for i in range(numFeatures):  # iterate over all the features

        featList = [example[i] for example in dataSet]  # create a list of all the examples of this feature

        uniqueVals = set(featList)  # get a set of unique values

        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  # calculate the info gain; ie reduction in entropy

        if (infoGain > bestInfoGain):  # compare this to the best gain so far

            bestInfoGain = infoGain  # if better than current best, set to best

            bestFeature = i

return bestFeature  # returns an integer

5 选择最好的方式划分数据集

  1. 递归构建决策树

createTree(dataSet, labels)递归函数,其功能是基于训练数据构建一棵决策树。这是决策树算法的核心实现部分,采用ID3算法的思想(通过信息增益选择特征)。

相关代码如下:

def createTree(dataSet, labels):

    classList = [example[-1] for example in dataSet]

    if classList.count(classList[0]) == len(classList):

        return classList[0]  # stop splitting when all of the classes are equal

    if len(dataSet[0]) == 1:  # stop splitting when there are no more features in dataSet

        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[:]  # copy all of labels, so trees don't mess up existing labels

        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)

    return myTree

6 构建决策树

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐