决策树

决策树是一种常用的机器学习算法,用于分类任务。它通过选择最佳特征进行递归划分,生成树形模型。常见算法包括ID3、C4.5和CART,分别使用信息增益、信息增益比和基尼指数作为特征选择标准。决策树的学习过程涉及特征选择、生成和剪枝,以防止过拟合。预剪枝和后剪枝是两种常用的剪枝策略,用于提高决策树的泛化能力。
摘要由CSDN通过智能技术生成

 

决策树

 

    决策树(decision tree)亦称“判定树”是一类常见的机器学习方法。以二分类任务为例,我们希望从给定训练集学得一个用以对新示例进行分类。比如根据书上的西瓜各种特征来最终得到这个瓜是不是好瓜。决策树的分类算法是基于实例的归纳学习算法。能从给定的一些完全无序的训练样本中,提炼出树形的分类模型。决策树的生成是一个递归的过程。树的非叶子节点记录了使用哪一个特征进行判断;叶子节点给出了最后的判断。决策树是一种监督学习

     决策树的学习过程主要是:

  1. 特征选择:选择哪个特征作为当前节点的判断依据
  2. 决策树生成:以递归的方式生成树
  3. 剪枝:解决“过拟合”的主要手段,主要有“预剪枝”和“后剪枝”

    常见的决策树算法分为ID3、 C4.5、CART算法,ID3算法主要是根据“信息增益“来选择特征的;C4.5算法是根据”信息增益比“来选择特征;而CART算法则是根据”基尼指数“来选择特征。

  • 特征选择
  1. 信息增益

“信息熵”是度量样本集合纯度最常用的一种指标。假定当前样本集合D中第k类样本所占的比例为pk(k=1,2,…),信息熵的定义为:

                                                                                        

Ent(D)的值越小,D的纯度越高。由此得到“信息增益”的公式:

                                                                            

信息增益越大,则意味着使用属性a来进行划分所获得的“纯度提升”越大。

ID3算法就是通过获得各个特征的“信息增益”的值,选择其中最大的作为当前非叶子节点的判断依据。

  1. 增益率

信息增益准则对可取值数目较多的属性有所偏好,为了减少这种偏好可能带来的不利影响。C4.5算法使用“增益率”来划分最优属性。增益率定义:

                                                                              

                                                                                 

IV(a)成为属性a的“固有值”,a的可能取值数目越多,则IV(a)的值通常会越大。注意:C4.5算法并不是直接选择增益率最大的属性作为候选划分属性,而是:先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的。

  1. 基尼指数

CART算法使用“基尼指数”来选择划分属性,并且选择基尼指数最小的那个属作为最优划分属性。数据集D的纯度可用基尼值来度量:

                                                                            

Gini(D)的意义是:从数据集D中随机抽取两个样本,其类别标记不一致的概率,因此,Gini(D)越小,数据集(D)纯度越高。

                                                                            

 

  • 决策树生成(ID3)

这里使用书上的那个西瓜例子  

数据集

def data_set():
    dataSet = [['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],
               ['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '是'],
               ['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],
               ['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '硬滑', '是'],
               ['浅白', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', '是'],
               ['青绿', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '是'],
               ['乌黑', '稍蜷', '浊响', '稍糊', '稍凹', '软粘', '是'],
               ['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '硬滑', '是'],
               ['乌黑', '稍蜷', '沉闷', '稍糊', '稍凹', '硬滑', '不是'],
               ['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘', '不是'],
               ['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑', '不是'],
               ['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘', '不是'],
               ['青绿', '稍蜷', '浊响', '稍糊', '凹陷', '硬滑', '不是'],
               ['浅白', '稍蜷', '沉闷', '稍糊', '凹陷', '硬滑', '不是'],
               ['乌黑', '稍蜷', '浊响', '清晰', '稍凹', '软粘', '不是'],
               ['浅白', '蜷缩', '浊响', '模糊', '平坦', '硬滑', '不是'],
               ['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑', '不是']]
    labels = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '是否好瓜']

    return dataSet, labels


 


#计算信息熵
def cal_entro(dataSet):
    num = len(dataSet)
    labels = {}

    #计算同一属性不同类别的个数
    for row in dataSet:
        label = row[-1]
        if label not in labels.keys():
            labels[label] = 0
        labels[label] += 1

    Ent = 0.0
    #计算信息熵
    for key in labels:
        prob = float(labels[key]) / num
        Ent -= prob * log(prob, 2)

    return Ent

#返回第i个特征的值为value的全部数据集
def split_dataSet(dataSet, i, value):
    ret_dataSet = []
    for row in dataSet:
        if row[i] == value:
            re_row = row[:i]
            re_row.extend(row[i+1:])
            ret_dataSet.append(re_row)

    return ret_dataSet

#选择最佳的特征
def choose_best_feature(dataSet):
    baseEnt = cal_entro(dataSet)
    bestFeature = -1
    bestGain = 0.0

    num = len(dataSet[0]) - 1
    for i in range(num):
        eveEnt = 0.0
        # 按历遍历数据集,选取一个特征的全部取值
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)

        for value in uniqueVals:
            sub_dataSet = split_dataSet(dataSet, i, value)
            prob = len(sub_dataSet) / float(len(dataSet))
            eveEnt += prob * cal_entro(sub_dataSet)

        #信息增益
        infoEnt = baseEnt - eveEnt
        if infoEnt > bestGain:
            bestFeature = i
            bestGain = infoEnt

    return bestFeature

#
def majorityCnt(classList):
    count = {}
    for value in classList:
        if value not in count.keys():
            count[value] = 0
        count[value] += 1

    sorted(count.items(), key=operator.itemgetter(1), reverse=True)

    return count[0][0]

#建立决策树
def create_tree(dataSet, labels):
    copylabels = labels[:]
    classList = [example[-1] for example in dataSet]
    #如果只有一种类别,则停止划分
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    #没有特征了
    if dataSet[0] == 1:
        return majorityCnt(classList)

    bestFeature = choose_best_feature(dataSet)
    bestLabel = copylabels[bestFeature] #最佳特征
    tree = {bestLabel:{}}
    del copylabels[bestFeature]

    featList = [example[bestFeature] for example in dataSet]
    uniquelVals = set(featList)

    for value in uniquelVals:
        copy2labels = copylabels[:]
        tree[bestLabel][value] = create_tree(split_dataSet(dataSet, bestFeature, value), copy2labels)

    return tree

#使用决策树来测试用例进行预测
def classify(tree, labels, testData):
    key = list(tree.keys())[0]
    dict = tree[key]
    featIndex = labels.index(key)
    for key in dict:
        if key == testData[featIndex]:
            if type(dict[key]).__name__ == 'dict':
                classLabel = classify(dict[key], labels, testData)
            else:
                classLabel = dict[key]

    return classLabel

if __name__ == '__main__':
    dataSet, labels = data_set()
    myTree = create_tree(dataSet, labels)
    print(myTree)
    treePlotter.createPlot(myTree)

    testData = ['浅白', '蜷缩', '清脆', '清晰', '平坦', '硬滑']
    result = classify(myTree, labels, testData)
    print(result)

 通过该算法最后生成一棵决策树,这是一棵训练好了的树,可以带入实例进行验证

决策树

    不过与树上的决策树不同的是:书上色泽有一个纯白分支,但是训练集中没有满足{清晰、稍蜷、纯白、......}的例子,所以上面的代码中训练不出来有该特征的分支。 

  • 剪枝

    剪枝(pruning)是决策树学习算法对付“过拟合”的主要手段。决策树剪枝的基本策略有“预剪枝”(prepruning)和“后剪枝”(postpruning)

预剪枝:决策树生成过程中,对每个节点在划分之前进行估计。若当前节点的划分不能带来决策树泛化性能提升,则停止划分并将当前节点作为叶节点标记。

编号色泽根蒂敲声纹理脐部触感好瓜
4青绿蜷缩沉闷清晰凹陷硬滑
5浅白蜷缩浊响清晰凹陷硬滑
8乌黑稍蜷浊响清晰稍凹硬滑
9乌黑稍蜷沉闷稍糊稍凹硬滑
11浅白硬挺清脆模糊平坦硬滑
12浅白蜷缩浊响模糊平坦软粘
13青绿稍蜷浊响稍糊凹陷硬滑

    以程序获得的决策树为例,假如在根节点不分的话,标记为好瓜(类别标记为训练样例最多的类别);则{4 5 8}的样例被分类正确。即accuracy=3/7=42.9%

    在用属性“纹理”划分之后,纹理的三个分支分别为{16},{7 14 17},{1 2 3 6 10 15 }分别被标记为“坏瓜” “坏瓜” “好瓜”,验证{4 5 8 9 11 12 13}accuracy=100%>42.9%,所以,用“纹理”进行划分得以确定。

    同理,继续比较,不过由于上一个已经是100%了,后面的一定不会比它大,所以最终结果直接得以确定,不用再分;不过这个100%是因为训练集和数据集太小,不足以说明情况

后剪枝:线直接生成一课完整的决策树,然后自底向上非叶子节点进行考察,若将该节点对应的子树替换成叶子节点能提高决策树的泛化能力,则将该节点替换为叶子节点。

    后剪枝同理,只不过后剪枝是自底向上,这里不再赘述

后剪枝通常要比预剪枝保留了更多的分支,后剪枝决策树的欠拟合风险很小,泛化能力往往优于预剪枝,但其训练时间开销比未剪枝和预剪枝决策树都要大。

    当训练集中有连续值的时候,使用连续属性离散化来进行处理;首先将该属性的所有值从小到大排序得到{a^{1},a^{2},...,a^{n}},通过划分点t将D分为子集D{t}^{-},D{t}^{+},其中一个装着所有比t小的值,另一个装所有比t大的值

将{a^{1},a^{2},...,a^{n}}中任意两个连续的值的中位数即,以课本机器学习P84中表4.3中的数据为例

 对于属性“密度”,将17个值从小到大排序,然后通过计算出T={0.244,0.294,0.351,... ... ,0.708,0.746}

,然后分别以为t将D分为两个子集,分别计算信息增益

比如以0.351为例:

 

挨个计算之后,选择最大的值作为属性“密度”的信息增益。

当训练集中有缺失值的时候,将某一属性非缺失的那些值按照原来的方法计算,然后在计算得到的Gain(D, a)的基础上乘以ρ

,Di为非缺失的数据项的数目,D为总数目;即为该属性的信息增益。

然后需要注意的是:在将某一个含有缺失值的属性标记为非叶子节点的时候,含有缺失值的那一项分配到每一个分支节点中,但是权重在各个节点中分别调整为(Di为该属性总的非缺失的项,Dj为该分支中含有的项).

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值