【机器学习】通过ID3,C4.5,CART算法构建决策树

(一)、决策树的简介

决策树(decision tree)是一种基本的分类与回归方法。决策树模型呈树形结构,在分类问题中,表示基于特征对实例进行分类的过程。它可以认为是if-then规则的集合,也可以认为是定义在特征空间与类空间上的条件概率分布。其主要优点是模型具有可读性,分类速度快。学习时,利用训练数据,根据损失函数最小化的原则建立决策树模型。预测时,对新的数据,利用决策树模型进行分类。决策树学习通常包括3个步骤:特征选择、决策树的生成和决策树的修剪。这些决策树学习的思想主要来源于由Quinlan在1986年提出的ID3算法和1993年提出的C4.5算法,以及由Breiman等人在1984年提出的CART算法。

决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。决策树是一种十分常用的分类回归方法

简单来说决策树就是一棵树,其中跟节点和内部节点是输入特征的判定条件,叶子结点就是最终结果。

优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理不相关特征数据。
缺点:可能会产生过度

(二)、构造决策树的三种构造方法

1.基于信息增益生成决策树(ID3算法)

信息增益是相对于特征而言的,信息增益越大,特征对最终的分类结果影响也就越大,我们就应该选择对最终分类结果影响最大的那个特征作为我们的分类特征。
提到信息增益必须先解释一下什么是“信息熵”,因为信息增益是基于信息熵而定义的。
信息熵的公式定义:
在这里插入图片描述
D:表示当前的数据集合。
k:表示当前数据集合中的第k类,也就是我们目标变量的类型。
这里根据公式算法得出一个数据集的信息熵

def calcShannonEnt(dataSet): 
    numEntries = len(dataSet)
    labelCounts = {}
    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
        shannonEnt -= prob * log(prob, 2)
    return shannonEnt

在这里插入图片描述
信息增益公式:在这里插入图片描述
这里通过ID3算法选择信息增益最大的特征,结果返回信息增益的最大索引。

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)
    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

导入自己的数据集,取数据集中的偶数项作为训练集,取奇数项作为测试集
下图为数据集中的某些数据展示,该数据为井字游戏残局数据集(数据集来源于UCI机器学习库
在这里插入图片描述

def file_train(filename):  # 取数据集偶数作为训练集
    fr = open(filename)
    lines = fr.readlines()
    res = []
    i = 0
    for line in lines:
        line = line.strip()
        temp = line.split(",")
        if i % 2 == 0:  # 取总数据集里的偶数
            res.append(temp)
        i += 1
    labels = ["top-left-square", "top-middle-square", "top-right-square",
     "middle-left-square", "middle-middle-square", "middle-right-square",
     "bottom-left-square","bottom-middle-square","bottom-right-square"]
    return res, labels

def file_test(filename):  # 取数据集的奇数作为测试集
    fr = open(filename)
    lines = fr.readlines()
    res = []
    i = 0
    for line in lines:
        line = line.strip()
        temp = line.split(",")
        if i % 2 == 1:  # 取总数据集里的奇数
            res.append(temp)
        i += 1
    labels = ["top-left-square", "top-middle-square", "top-right-square", "middle-left-square", "middle-middle-square", "middle-right-square","bottom-left-square","bottom-middle-square","bottom-right-square"]
    return res, labels

运行结果:
生成的决策树
在这里插入图片描述
训练模型精度
可以看出基于信息增益训练出来的模型正确率为84.76%
在这里插入图片描述

2.基于信息增益率生成决策树(C4.5算法)

C4.5算法继承了ID3算法的优点,并在以下几方面对ID3算法进行了改进:

1) 用信息增益率来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性的不足;
2) 能够完成对连续属性的离散化处理;
3) 能够对不完整数据进行处理。

优点:
产生的分类规则易于理解,准确率较高。
缺点:
在构造树的过程中,需要对数据集进行多次的顺序扫描和排序,因而导致算法的低效。此外,C4.5只适合于能够驻留于内存的数据集,当训练集大得无法在内存容纳时程序无法运行。
信息增益率公式:
在这里插入图片描述
采用了一个启发式方法:先从候选划分属性中找出信 息增益高于平均水平的属性,再从中选取增益率最高的。

以下是C4.5算法代码,C4.5算法核心代码相较于ID3核心算法代码差距不大

def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1 
    baseEntropy = calcShannonEnt(dataSet)
    bestinfoGainratio = 0.0
    bestFeature = -1 
    for i in range(numFeatures):#遍历所有的特征
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList) 
        newEntropy = 0.0 
        IV = 0.0
        for value in uniqueVals:#遍历该特征维度下对应的所有特征值
            subDataSet = splitdataSet(dataSet, i, value)
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob * calcShannonEnt(subDataSet)#计算每个子集对应的信息熵,并全部相加,得到划分后数据的信息熵
            IV -= prob * log(prob,2)
        infoGain = baseEntropy - newEntropy#将原数据的信息熵-划分后数据的信息熵,得到信息增益
        if IV == 0.0:
            infoGainratio = 0.0
        else:
            infoGainratio = float(infoGain) / float(IV)
        if (infoGainratio > bestinfoGainratio):#如果这个信息增益率比当前记录的最佳信息增益率还大,就将该增益和划分依据的特征记录下来
            bestinfoGainratio = infoGainratio#更新信息增益率,找到最大的信息增益率
            bestFeature = i
    return bestFeature

运行结果:
生成的决策树
在这里插入图片描述
训练模型精度
由实验结果可以看出基于信息增益率训练出的模型正确率达到86.22%,相较于信息增益训练出来的模型正确率高了近2个百分点。
在这里插入图片描述

3.基于基尼指数生成决策树(CART算法)

CART(Classification And Regression Tree)分类回归树算法的最优特征选择方法
对于C4.5算法,我们也提到了它的不足,比如模型是用较为复杂的熵来度量,使用了相对较为复杂的多叉树,只能处理分类不能处理回归等。对于这些问题, CART算法大部分做了改进。

基尼指数,又称基尼不纯度,其计算和信息熵的类似,但是计算的速度会超过信息熵,因为没有计算对数的操作。基尼不纯度为这个样本被选中的概率乘以它被分错的概率,可以作为衡量不确定性大小的标准。当一个节点中所有样本都是一个类时,基尼不纯度为0。

对于给定的样本集合D,其基尼指数为:
在这里插入图片描述
将样本分为D1、D2,即将该属性的一个属性值抽出与其它属性值进行概率分布基尼指数的计算。该基尼指数表示经过特征A的某个取值分割集合D后的不确定性。
在这里插入图片描述
CART算法实现:

def calcProbabilityEnt(dataSet):
    numEntries = len(dataSet)
    feaCounts = 0
    fea1 = dataSet[0][len(dataSet[0])-1]
    for feaVec in dataSet:
        if feaVec[-1] == fea1:
            feaCounts += 1
    probabilityEnt = float(feaCounts) / numEntries
    return probabilityEnt
    
#选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1  #特征数量,numfeature为特征的维度,因为最后一列为标签,所以需要减去1
    if numFeatures == 1: 
        return 0
    bestGini = 1     #最佳基尼指数
    bestFeature = -1     #最优的划分特征初始化为-1
    for i in range(numFeatures):   #遍历所有的特征
        featList = [example[i] for example in dataSet]
        feaGini = 0    #定义特征的值的基尼系数
        uniqueVals = set(featList) 
        for value in uniqueVals: #遍历该特征维度下对应的所有特征值
            subDataSet = splitDataSet(dataSet, i, value)
            prob = len(subDataSet)/float(len(dataSet))
            probabilityEnt = calcProbabilityEnt(subDataSet)
            feaGini += prob * (2 * probabilityEnt * (1 - probabilityEnt))
        if (feaGini < bestGini):
            bestGini = feaGini
            bestFeature = i   #记录基尼指数最小的索引值
    return bestFeature

运行截图:
生成的决策树
在这里插入图片描述
训练模型精度
可以看出基于基尼指数训练出来的模型精准度为83.3%。
在这里插入图片描述

总结

在ID3算法中我们使用了信息增益来选择特征,信息增益大的优先选择。
在C4.5算法中,采用了信息增益比来选择特征,以减少信息增益容易选择特征值多的特征的问题。
但是无论是ID3还是C4.5,都是基于信息论的熵模型的,这里面会涉及大量的对数运算。
在CART算法中,CART分类树算法使用基尼系数来代替信息增益比,基尼系数代表了模型的不纯度,基尼系数越小,则不纯度越低,特征越好。这和信息增益(比)是相反的。

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
决策树是一种常见的机器学习算法,其中ID3C4.5和CART是三种常见的决策树分类算法。下面是它们的Python代码介绍: 1. ID3算法代码: ``` def ID3(data, labels): # 计算数据集的信息熵 entropy = calcEntropy(data) # 如果数据集的信息熵为0,则直接返回该数据集的类别 if entropy == 0: return data[0][-1] # 如果特征集为空,则返回数据集中出现次数最多的类别 if len(labels) == 0: return majorityClass(data) # 选择最优划分特征 bestFeature = chooseBestFeature(data, labels) # 根据最优特征生成决策树 decisionTree = {bestFeature: {}} # 从特征集中删除已经使用的特征 labels.remove(bestFeature) # 获取最优特征的所有取值 featureValues = set([example[bestFeature] for example in data]) # 遍历最优特征的所有取值,生成子树 for value in featureValues: subLabels = labels[:] decisionTree[bestFeature][value] = ID3(splitData(data, bestFeature, value), subLabels) return decisionTree ``` 2. C4.5算法代码: ``` def C45(data, labels): # 计算数据集的信息熵 entropy = calcEntropy(data) # 如果数据集的信息熵为0,则直接返回该数据集的类别 if entropy == 0: return data[0][-1] # 如果特征集为空,则返回数据集中出现次数最多的类别 if len(labels) == 0: return majorityClass(data) # 选择最优划分特征 bestFeature = chooseBestFeature(data, labels) # 根据最优特征生成决策树 decisionTree = {bestFeature: {}} # 从特征集中删除已经使用的特征 labels.remove(bestFeature) # 获取最优特征的所有取值 featureValues = set([example[bestFeature] for example in data]) # 遍历最优特征的所有取值,生成子树 for value in featureValues: subLabels = labels[:] # 计算每个取值的信息增益率 subData = splitData(data, bestFeature, value) ratio = calcRatio(subData, entropy) # 如果信息增益率高于平均水平,则生成子树 if ratio >= averageRatio(data, bestFeature): decisionTree[bestFeature][value] = C45(subData, subLabels) # 否则返回数据集中出现次数最多的类别 else: decisionTree[bestFeature][value] = majorityClass(subData) return decisionTree ``` 3. CART算法代码: ``` def CART(data, labels): # 如果数据集中只有一个类别,则直接返回该类别 if len(set([example[-1] for example in data])) == 1: return data[0][-1] # 如果特征集为空,则返回数据集中出现次数最多的类别 if len(labels) == 0: return majorityClass(data) # 选择最优划分特征 bestFeature, bestValue, bestScore = chooseBestSplit(data) # 根据最优特征生成决策树 decisionTree = {bestFeature: {}} # 从特征集中删除已经使用的特征 labels.remove(bestFeature) # 生成左子树和右子树 leftData = [example for example in data if example[bestFeature] <= bestValue] rightData = [example for example in data if example[bestFeature] > bestValue] decisionTree[bestFeature]['left'] = CART(leftData, labels) decisionTree[bestFeature]['right'] = CART(rightData, labels) return decisionTree ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打代码能当饭吃?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值