决策树(Decision Tree)算法详解及python实现

简介: 决策树(Decision Tree)算法详解及python实现

一、决策树概述


策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。


分类树(决策树)是一种十分常用的分类方法。他是一种监督学习,所谓监督学习就是给定一堆样本,每个样本都有一组属性和一个类别,这些类别是事先确定的,那么通过学习得到一个分类器,这个分类器能够对新出现的对象给出正确的分类。这样的机器学习就被称之为监督学习。


机器学习中,决策树是一个预测模型;他代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分叉路径则代表的某个可能的属性值,而每个叶结点则对应从根节点到该叶节点所经历的路径所表示的对象的值。决策树仅有单一输出,若欲有复数输出,可以建立独立的决策树以处理不同输出。数据挖掘中决策树是一种经常要用到的技术,可以用于分析数据,同样也可以用来作预测。


从数据产生决策树的机器学习技术叫做决策树学习, 通俗说就是决策树。


一个决策树包含三种类型的节点:


决策节点:通常用矩形框来表示


机会节点:通常用圆圈来表示


终结点:通常用三角形来表示


决策树学习也是资料探勘中一个普通的方法。在这里,每个决策树都表述了一种树型结构,它由它的分支来对该类型的对象依靠属性进行分类。每个决策树可以依靠对源数据库的分割进行数据测试。这个过程可以递归式的对树进行修剪。 当不能再进行分割或一个单独的类可以被应用于某一分支时,递归过程就完成了。另外,随机森林分类器将许多决策树结合起来以提升分类的正确率。


概述一般看文字有点难懂,那让我们来理解一下它的工作原理就很好理解了。


二、工作原理及特点


决策树的工作原理与你问我答缩小范围类似,用户输入一系列数据,然后给出自己偏好。有点像以前学C的小算法猜闰年相似。

20201012103411570.png



决策树的主要优势就在于数据形式非常容易理解。因此决策树可以使用不熟悉的数据集合,并从中提取出一系列规则。

决策树的特点:

  • 优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。
  • 缺点:可能会产生过度匹配的问题
  • 适用数据类型:数值型和标称型


三、决策树的构造


在构造决策树时,我们要抓住问题,也就是得到答案的关键性问题,划分出最好的结果。因此我们必须评估每个特征,找出最优的划分结果。根据决策树伪代码可知:


20201012104721238.png

从中分析可知该算法是一个递归分类算法,有三种情况会导致递归返回:


1.该分支下的数据的属性标签全为一类,则停止划分。


2.当询问完所有问题特征后,特征列表为空,则停止划分,选举属性标签出现频率最多的为叶节点。


3.当前节点包含的样本集合为空,标记当前节点为叶节点,并将其类别设为父节点所含样例最多的类别。


四、信息增益


了解完决策树基本工作原理和构造方法后,现在要了解如何处理数据使得数据更有利用效率被决策树使用。划分数据集的大原则是:将无需的数据变得更加有序。我们得找出划分数据集最关键的特征,也就是询问别人最高效区分类别的问题。首先我们得要有一个关于如何度量信息有序程度的变量。


信息熵:这里不作过多关于热力学方面的解释,仅针对信息。信息熵定位为信息的期望值。假定当前样本集合D中第k类样本所占的比例为pk(k = 1,2,...,|Y|),则D的信息熵定义为:


20201013003202998.png



对于底数之所以取2,一般的理解是,因为信息按照计算机表示采用的是二进制形式。由定义可推知,Ent(D)的值越小,则D的纯度越高。


在理解信息增益之前,要明确——条件熵


信息增益表示得知特征X的信息而使得类Y的信息不确定性减少的程度。


条件熵H ( Y ∣ X ) H(Y|X)H(Y∣X)表示在已知随机变量X的条件下随机变量Y的不确定性,随机变量X给定的条件下随机变量Y的条件熵(conditional entropy) H(Y|X),定义X给定条件下Y的条件概率分布的熵对X的数学期望:

20201019142353674.png


其中,


20201019142419480.png


当熵和条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的分别为经验熵和经验条件熵,此时如果有0概率,令0log0=0.


在此基础上,给出“信息增益”(information gain)的定义:


假定离散属性a有V种不同的取值{a1, a2, ..., aV},使用a对D进行划分,则会产生V个分支节点,其中第v个分支节点包含D中属性值为av的样本,记为Dv,则用属性a对样本集D进行划分所获得的信息增益定义为:

20201013004202458.png

一般而言,信息增益越大,则意味着使用属性a来进行划分所获得的纯度提升越大。于是,我们便可以按信息增益来选择决策树的划分属性。相关的算法有著名的ID3算法[Quinlan, 1986]。


然而事实上,信息增益对可取值数目较多的属性有所偏好。这种偏好可能会降低模型的泛化能力。为减少这种偏好带来的不利影响,著名的C4.5决策树算法[Quinlan, 1993]不直接使用信息增益,而使用“增益率”(gain ratio)来划分最优属性。下面引入增益率的概念。(决策树(decision tree) - 剪开黑夜 - 博客园)


由于本篇仅使用信息增益划分数据集,另外两种度量方式增益率和基尼系数不作过多解释,有兴趣的可以看上面大佬博客。


五、决策树实现


了解了上面基础知识差不多可以构建树了,决策树的剪枝处理和连续与缺失值等优化问题先不作讨论。

这里我们模拟小部分数据:


20201013005537290.png


根据这些数据我们来慢慢构造决策树,最后实现其主要功能。


1.构造数据集


将上述数据转为列表,当然例子数据比较简单,其他数据做不同处理。


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

2.计算熵值


为该类数据分类最好使用数据字典来保存分类结果。


def calcShannonEnt(dataSet):
    numEntries = len(dataSet)
    labelCounts = {} #创建记录不同分类标签结果多少的字典
    #为所有可能分类保存
    #该字典key:label value:label的数目
    for featVec in dataSet:
        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 #标签发生概率p(xi)的值
        shannonEnt -= prob * log(prob,2)
    return shannonEnt #熵

代码实现和上述熵计算一致。测试该数据集未分类之前的熵:

20201013010818453.png

当然可以根据改动原有数据集标签来测试熵值的波动:


20201013011014857.png

2020101301102896.png

可发现数据越混乱熵值越高。


3.按特征划分数据

def splitDataSet(dataSet , axis ,value):#axis代表第几个特征 value为结果
    #避免修改原始数据集创建新数据集
    retDataSet = []
    #抽取符合特征的数据集
    for featVec in dataSet:
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet


可以说就是挑选出符合特征的数据集然后将自身特征值抛出列表。

我们可以试试效果:


a=splitDataSet(dataSet,1,0)
print(a)

[[1, 'yes'], [1, 'yes'], [0, 'no']]


没问题。


4.选择最优划分算法


如何就是决策树的重点,如何选择最优的划分方式,也就是选择信息增益最大化的方式,通过for循环对不同的特征值进行划分,计算每种方式的信息熵,然后取得最大信息增益划分方式,计算最好的信息增益,返回最好特征划分的索引值。


#选择最好的数据集划分方式
def 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) #划分
            prob = len(subDataSet)/float(len(dataSet)) #同特征下不同回答所占总回答比率
            newEntropy += prob * calcShannonEnt(subDataSet) #该特征划分下的信息熵
        infoGain = baseEntropy - newEntropy #信息增益
        if ( infoGain > bestInfoGain ):
                bestInfoGain =infoGain
                bestFeature = i
    return bestFeature
MydDat,labels=createDataSet()
print(chooseBestFeatureToSplit(MydDat))


得知最好的划分特征为第一个特征,所以第一次以第一个特征进行询问。


5.构造决策树


给张图更好理解:

20201013102645222.png


在构造树之前对于递归返回条件第二条:当询问完所有问题特征后,特征列表为空,则停止划分,选举属性标签出现频率最多的为叶节点。当遍历完所有特征时,要返回出现次数最多的分类名称。因此要构造选举函数:


def majorityCnt(classList):
    classCount={}
    for vote in classList:
        if vote not in classCount.key():classCount[vote] = 0
        classCount[vote] +=1
    sortedClassCount = sorted(classCount.items(),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


输出结果为:


{'no surfacing ': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}}


决策树构造完成。


总结


但仅仅是用数据字典表示还是不能很好的直观展示决策树,我将在下一篇文章写道如何使用Matplotlib注解绘制树形图以及决策树实例运用。

目录
相关文章
|
11天前
|
机器学习/深度学习 人工智能 算法
猫狗宠物识别系统Python+TensorFlow+人工智能+深度学习+卷积网络算法
宠物识别系统使用Python和TensorFlow搭建卷积神经网络,基于37种常见猫狗数据集训练高精度模型,并保存为h5格式。通过Django框架搭建Web平台,用户上传宠物图片即可识别其名称,提供便捷的宠物识别服务。
142 55
|
26天前
|
搜索推荐 Python
利用Python内置函数实现的冒泡排序算法
在上述代码中,`bubble_sort` 函数接受一个列表 `arr` 作为输入。通过两层循环,外层循环控制排序的轮数,内层循环用于比较相邻的元素并进行交换。如果前一个元素大于后一个元素,就将它们交换位置。
126 67
|
26天前
|
存储 搜索推荐 Python
用 Python 实现快速排序算法。
快速排序的平均时间复杂度为$O(nlogn)$,空间复杂度为$O(logn)$。它在大多数情况下表现良好,但在某些特殊情况下可能会退化为最坏情况,时间复杂度为$O(n^2)$。你可以根据实际需求对代码进行调整和修改,或者尝试使用其他优化策略来提高快速排序的性能
118 61
|
28天前
|
算法 数据安全/隐私保护 开发者
马特赛特旋转算法:Python的随机模块背后的力量
马特赛特旋转算法是Python `random`模块的核心,由松本真和西村拓士于1997年提出。它基于线性反馈移位寄存器,具有超长周期和高维均匀性,适用于模拟、密码学等领域。Python中通过设置种子值初始化状态数组,经状态更新和输出提取生成随机数,代码简单高效。
105 63
|
20天前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
110 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
1月前
|
机器学习/深度学习 算法 大数据
蓄水池抽样算法详解及Python实现
蓄水池抽样是一种适用于从未知大小或大数据集中高效随机抽样的算法,确保每个元素被选中的概率相同。本文介绍其基本概念、工作原理,并提供Python代码示例,演示如何实现该算法。
35 1
|
1月前
|
数据采集 数据可视化 数据挖掘
掌握Python数据分析,解锁数据驱动的决策能力
掌握Python数据分析,解锁数据驱动的决策能力
|
1天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
102 80
|
20天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
6天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。