cart(决策分类树)原理和实现

2BiTT 2BiTT     2022-08-09     284

关键词:

前面我们了解了决策树和adaboost的决策树墩的原理和实现,在adaboost我们看到,用简单的决策树墩的效果也很不错,但是对于更多特征的样本来说,可能需要很多数量的决策树墩

或许我们可以考虑使用更加高级的弱分类器,下面我们看下CART(Classification And Regression Tree)的原理和实现吧

CART也是决策树的一种,不过是满二叉树,CART可以是强分类器,就跟决策树一样,但是我们可以指定CART的深度,使之成为比较弱的分类器

CART生成的过程和决策树类似,也是采用递归划分的,不过也存在很多的不同之处

数据集:第一列为样本名称,最后一列为类别,中间为特征

human    constant    hair    true    false    false    false    true    false    mammal
python    cold_blood    scale    false    true    false    false    false    true    reptile
salmon    cold_blood    scale    false    true    false    true    false    false    fish
whale    constant    hair    true    false    false    true    false    false    mammal
frog    cold_blood    none    false    true    false    sometime    true    true    amphibious
lizard    cold_blood    scale    false    true    false    false    true    false    reptile
bat    constant    hair    true    false    true    false    true    false    mammal
cat    constant    skin    true    false    false    false    true    false    mammal
shark    cold_blood    scale    true    false    false    true    false    false    fish
turtle    cold_blood    scale    false    true    false    sometime    true    false    reptile
pig    constant    bristle    true    false    false    false    true    true    mammal
eel    cold_blood    scale    false    true    false    true    false    false    fish
salamander    cold_blood    none    false    true    false    sometime    true    true    amphibious

 

特征名称如下

["temperature","cover","viviparity","egg","fly","water","leg","hibernate"]

 

1:数据集划分评分

CART使用gini系数来衡量数据集的划分效果而不是香农熵(借用下面的一张图)

def calGini(dataSet):
    numEntries = len(dataSet)
    labelCounts={}
    for featVec in dataSet: 
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1
    gini=1
    for label in labelCounts.keys():
        prop=float(labelCounts[label])/numEntries
        gini -=prop*prop
    return gini

 

2:数据集划分

决策树是遍历每一个特征的特征值,每个特征值得到一个划分,然后计算每个特征的信息增益从而找到最优的特征;

CART每一个分支都是二分的,当特征值大于两个的时候,需要考虑特征值的组合得到两个“超级特征值”作为CART的分支;当然我们也可以偷懒,每次只取多个特征值的一个,挑出最优的一个和剩下的分别作为一个分支,但无疑这得到的cart不是最优的

# 传入的是一个特征值的列表,返回特征值二分的结果
def featuresplit(features):
    count = len(features)#特征值的个数
    if count < 2:
        print "please check sample's features,only one feature value"
        return -1
    # 由于需要返回二分结果,所以每个分支至少需要一个特征值,所以要从所有的特征组合中选取1个以上的组合
    # itertools的combinations 函数可以返回一个列表选多少个元素的组合结果,例如combinations(list,2)返回的列表元素选2个的组合
    # 我们需要选择1-(count-1)的组合
    featureIndex = range(count)
    featureIndex.pop(0) 
    combinationsList = []    
    resList=[]
    # 遍历所有的组合
    for i in featureIndex:
        temp_combination = list(combinations(features, len(features[0:i])))
        combinationsList.extend(temp_combination)
        combiLen = len(combinationsList)
    # 每次组合的顺序都是一致的,并且也是对称的,所以我们取首尾组合集合
    # zip函数提供了两个列表对应位置组合的功能
    resList = zip(combinationsList[0:combiLen/2], combinationsList[combiLen-1:combiLen/2-1:-1])
    return resList

 

得到特征的划分结果之后,我们使用二分后的特征值划分数据集

def splitDataSet(dataSet, axis, values):
    retDataSet = []
    for featVec in dataSet:
        for value in values:
            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      #
    bestGiniGain = 1.0; bestFeature = -1;bestBinarySplit=()
    for i in range(numFeatures):        #遍历特征
        featList = [example[i] for example in dataSet]#得到特征列
        uniqueVals = list(set(featList))       #从特征列获取该特征的特征值的set集合
        # 三个特征值的二分结果:
        # [(('young',), ('old', 'middle')), (('old',), ('young', 'middle')), (('middle',), ('young', 'old'))]
        for split in featuresplit(uniqueVals):
            GiniGain = 0.0
            if len(split)==1:
                continue
            (left,right)=split
            # 对于每一个可能的二分结果计算gini增益
            # 左增益
            left_subDataSet = splitDataSet(dataSet, i, left)
            left_prob = len(left_subDataSet)/float(len(dataSet))
            GiniGain += left_prob * calGini(left_subDataSet)
            # 右增益
            right_subDataSet = splitDataSet(dataSet, i, right)
            right_prob = len(right_subDataSet)/float(len(dataSet))
            GiniGain += right_prob * calGini(right_subDataSet)
            if (GiniGain <= bestGiniGain):       #比较是否是最好的结果
                bestGiniGain = GiniGain         #记录最好的结果和最好的特征
                bestFeature = i
                bestBinarySplit=(left,right)
    return bestFeature,bestBinarySplit    

 所有特征用完时多数表决程序

def majorityCnt(classList):
    classCount={}
    for vote in classList:
        if vote not in classCount.keys(): classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

现在来生成cart吧

 

def createTree(dataSet,labels):
    classList = [example[-1] for example in dataSet]
    # print dataSet
    if classList.count(classList[0]) == len(classList): 
        return classList[0]#所有的类别都一样,就不用再划分了
    if len(dataSet) == 1: #如果没有继续可以划分的特征,就多数表决决定分支的类别
        # print "here"
        return majorityCnt(classList)
    bestFeat,bestBinarySplit = chooseBestFeatureToSplit(dataSet)
    # print bestFeat,bestBinarySplit,labels
    bestFeatLabel = labels[bestFeat]
    if bestFeat==-1:
        return majorityCnt(classList)
    myTree = {bestFeatLabel:{}}
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = list(set(featValues))
    for value in bestBinarySplit:
        subLabels = labels[:]       # #拷贝防止其他地方修改
        if len(value)<2:
            del(subLabels[bestFeat])
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
    return myTree 

 

看下效果,左边是cart,右边是决策树,(根节点用cover和temperature是一样的,为了对比决策树,此时我选了cover),第三个图是temperature作为根节点的cart

上面的代码是不考虑特征继续使用的,也就是每个特征只使用一次;但是我们发现有些有些分支里面特征值个数多余两个的,其实我们应该让这些特征继续参与下一次的划分

可以发现,temperature作为根节点的cart没有变化,而cover作为根节点的cart深度变浅了,并且cover特征出现了两次(或者说效果变好了)

 下面是有变化的代码

特征值多余两个的分支保留特征值

def splitDataSet(dataSet, axis, values):
    retDataSet = []
    if len(values) < 2:
        for featVec in dataSet:
            if featVec[axis] == values[0]:#如果特征值只有一个,不抽取当选特征
                reducedFeatVec = featVec[:axis]     
                reducedFeatVec.extend(featVec[axis+1:])
                retDataSet.append(reducedFeatVec)
    else:
        for featVec in dataSet:
            for value in values:
                if featVec[axis] == value:#如果特征值多于一个,选取当前特征
                    retDataSet.append(featVec)

    return retDataSet

 

createTree函数for循环判断是否需要移除当前最优特征

    for value in bestBinarySplit:
        if len(value)<2:
            del(labels[bestFeat])
        subLabels = labels[:]       #拷贝防止其他地方修改
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)

 

这样我们就生成了一个cart,但是这个数据集没有出现明显的过拟合的情景,我们换一下数据集看看

sunny    hot    high    FALSE    no
sunny    hot    high    TRUE    no
overcast    hot    high    FALSE    yes
rainy    mild    high    FALSE    yes
rainy    cool    normal    FALSE    yes
rainy    cool    normal    TRUE    no
overcast    cool    normal    TRUE    yes
sunny    mild    high    FALSE    no
sunny    cool    normal    FALSE    yes
rainy    mild    normal    FALSE    yes
sunny    mild    normal    TRUE    yes
overcast    mild    high    TRUE    yes
overcast    hot    normal    FALSE    yes
rainy    mild    high    TRUE    no

 

 特征名称:"Outlook" , "Temperature" , "Humidity" , "Wind"

生成的cart比价合理,这是因为数据比较合理,我们添加一条脏数据看看cart会变成怎么样(右图),可以看到cart为了拟合我新加的这条脏数据,

树深度增加1,叶子节点增加3,不过另一方面也是因为样本数少的原因,一个噪声样本就产生了如此大的印象

overcast    mild    normal    FALSE    no

下一篇博客我们继续讨论cart连续值的生成以及剪枝的实验。

 

决策树(id3,c4.5,cart)原理以及实现(代码片段)

决策树决策树是一种基本的分类和回归方法.决策树顾名思义,模型可以表示为树型结构,可以认为是if-then的集合,也可以认为是定义在特征空间与类空间上的条件概率分布.[图片上传失败...(image-2e6565-1543139272117)]决策树的中间节点可... 查看详情

机器学习——决策树(下)算法实现

Decisiontree在机器学习(5)——决策树(上)原理中介绍了决策树的生成和剪枝原理。介绍了CART,ID3,C4.5等算法的算法流程,其中CART算法可以实现回归和分类,是基于基尼不纯度实现的,这里并未实... 查看详情

决策树算法

 在决策树算法原理(上)这篇里,我们讲到了决策树里ID3算法,和ID3算法的改进版C4.5算法。对于C4.5算法,我们也提到了它的不足,比如模型是用较为复杂的熵来度量,使用了相对较为复杂的多叉树,只能处理分类不能处理回归... 查看详情

决策树(主要针对cart)的生成与剪枝

这次主要想写两篇,一篇把决策树的相关思想和方法解释清楚,另外一个说一下ensemble形式的决策树,randomforest,依据主要是breiman的论文。这篇讲决策树(主要以cart为例,因为randomforest的大多实现也是根据cart)1、cart的生成。ca... 查看详情

课时决策树和随机森林

决策树通常决策树主要有三种实现,分别是ID3算法,CART算法和C4.5算法。随机森林的重点在于单个决策树是如何建造的CARTClassificationAndRegressionTree,即分类回归树算法,简称CART算法,它是决策树的一种实现.CART算法是一种二分递... 查看详情

机器学习决策树分类原理(代码片段)

决策树分类原理1.熵1.1概念1.2案例2.决策树的划分依据2.1信息增益2.1.1概念2.1.2案例2.2信息增益率2.2.1概念2.2.2案例案例一案例二2.2.3为什么使用C4.5要好?2.3基尼值和基尼指数2.3.1概念2.3.2案例3.小结3.1常见决策树的启发函数比较3.1.1ID3... 查看详情

机器学习笔记之三cart分类与回归树

...本的类别,回归树的输出是一个实数。CART算法有两步:决策树生成和剪枝。决策树生成:递归地构建二叉决策树的过程,基于训练数据集生成决策树,生成的决策树要尽量大;自上而下 查看详情

实验三:cart分类决策树python实现(两个测试集)|机器学习(代码片段)

目录python实现分步源代码(全部)测试集1(鸢尾花集)测试集2(红酒品类数据集)总结python实现分步划分数据子集(注意区分离散特征值和连续特征值)#获取数据子集,分类与回归的做法相同... 查看详情

决策树算法

 决策树算法在机器学习中算是很经典的一个算法系列了。它既可以作为分类算法,也可以作为回归算法,同时也特别适合集成学习比如随机森林。本文就对决策树算法原理做一个总结,上篇对ID3,C4.5的算法思想做了总结,下... 查看详情

数据挖掘十大经典算法--cart:分类与回归树

一、决策树的类型 在数据挖掘中,决策树主要有两种类型:分类树的输出是样本的类标。回归树的输出是一个实数(比如房子的价格,病人呆在医院的时间等)。术语分类和回归树(CART)包括了上述两种决策树,最先由Breiman等... 查看详情

cart分类与回归树

...本的类别,回归树的输出是一个实数。CART算法有两步:决策树生成和剪枝。决策树生成:递归地构建二叉决 查看详情

决策树原理及实现

      1、决策树原理1.1、定义 分类决策树模型是一种描述对实例进行分类的树形结构。决策树由结点和有向边组成。结点有两种类型:内部节点和叶节点,内部节点表示一个特征或属性,叶节点表示一... 查看详情

机器学习——决策树(上)原理

Decisiontree决策树是机器学习中一种基本的分类和回归算法,是依托于策略抉择而建立起来的树。其主要优点是模型具有可读性,分类速度快,易于理解。决策树的思想主要来源于Quinlan在1986年提出的ID3算法和1993年提出... 查看详情

机器学习总结决策树id3,c4.5算法,cart算法

本文主要总结决策树中的ID3,C4.5和CART算法,各种算法的特点,并对比了各种算法的不同点。决策树:是一种基本的分类和回归方法。在分类问题中,是基于特征对实例进行分类。既可以认为是if-then规则的集合,也可以认为是定... 查看详情

机器学习笔记——cart树

...  (1)CART树只能够生成2个结点,即CART树是一棵二叉决策树,而后两者在进行划分时可以根据特征值的种类生成2个以上的结点。  (2)CART分类树的划分依据是基尼指数(Giniindex)最小化准则,而后两者是根据熵的最小化... 查看详情

《机器学习》(周志华)第4章决策树笔记理论及实现——“西瓜树”——cart决策树

CART决策树(一)《机器学习》(周志华)第4章决策树笔记理论及实现——“西瓜树”参照上一篇ID3算法实现的决策树(点击上面链接直达),进一步实现CART决策树。其实只需要改动很小的一部分就可以了,把原先计算信息熵和... 查看详情

数据挖掘领域经典算法——cart算法

简介CART与C4.5类似,是决策树算法的一种。此外,常见的决策树算法还有ID3,这三者的不同之处在于特征的划分:ID3:特征划分基于信息增益C4.5:特征划分基于信息增益比CART:特征划分基于基尼指数基本思想CART假设决策树是二... 查看详情

数据挖掘领域经典算法——cart算法

简介CART与C4.5类似,是决策树算法的一种。此外,常见的决策树算法还有ID3,这三者的不同之处在于特征的划分:ID3:特征划分基于信息增益C4.5:特征划分基于信息增益比CART:特征划分基于基尼指数基本思想CART假设决策树是二... 查看详情