《李航 统计学习方法》学习笔记——第五章决策树

5.1 决策树模型与学习

分类决策树模型是一种描述对实例进行分类得树形结构。内部节点表示一个特征或属性,叶子节点表示一个类。
在这里插入图片描述
路径上内部节点的特征对应着规则的结论,而叶节点的类对应着规则的结论。决策树的路径具有一个重要的性质:互斥并且完备,每一个实例都被一条路径或一条规则所覆盖,且只被一条路径或一条规则所覆盖。

  • 决策树与条件概率
    决策树还可以表示给定特征条件下类的条件概率分布。下图中(a)的大正方形表示特征空间,每个小矩形表示一个单元。假设 Y Y Y的取值只有-1和+1,小矩形中的式子表示单元的类。(b)图表示特征空间划分确定时,特征单元给定下的条件概率分布。当某个单元 c c c的条件概率满足 P ( Y = + 1 ∣ X = c ) > 0.5 P(Y=+1|X=c)>0.5 P(Y=+1X=c)>0.5时,落在这个单元的实例都被视为+1。
    在这里插入图片描述
  • 决策树学习
    决策树学习本质上是从训练数据集中归纳出一组分类规则。决策树可能不止一个也可能一个都没有,所以目标是找到与训练数据矛盾较小的决策树,同时具有很好的泛化能力。
    学习过程:
    (1)首先构造根节点,将所有训练数据都放在根节点。
    (2)选取一个最优特征,按照这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。
    (3)若这些子集能够被基本正确分类,那么构建叶子节点,并将这些子集分到所对应的叶子节点中去;如果还有子集不能被基本正确分类,那么就对这些子集选择新的最优特征,继续进行分割,构建相应的结点。
    (4)递归(2)(3),知道所有训练数据子集被基本正确分类,或者没有合适的特征。
    通过这样生成的决策树,虽然对训练数据有较好的拟合效果,但是对于测试数据可能会发生过拟合现象,所以需要适当的对树进行剪枝,去掉过于细分的叶子节点。
    决策树的生成对应于模型的局部选择(当前分割后损失函数最小化为目的),决策树的剪枝对应于模型的全局选择(测试集上的损失函数尽可能小)
  • 决策树学习算法:特征选择、决策树的生成、决策树的剪枝

5.2 特征选择

特征选取的目的:选取对训练数据具有分类能力的特征,提高决策树学习的效率。常见的选择指标为信息增益信息增益比

5.2.1 信息增益

  • 熵:表示随机变量不确定性的度量,熵越大,随机变量的不确定性越大,数据混乱程度越大,不整齐;且熵仅依赖于X的分布,与X的取值范围无关。
    P ( X = x i ) = p i     i = 1 , 2 , . . . . n H ( X ) = − ∑ i = 1 n p i log ⁡ p i P(X=x_i)=p_i\ \ \ i=1,2,....n\\ H(X)=-\sum\limits_{i=1}^{n}p_i\log p_i P(X=xi)=pi   i=1,2,....nH(X)=i=1npilogpi
    H ( X ) H(X) H(X)即为随机变量X的熵。
    P ( X = x i , Y = y i ) = p i j     i = 1 , 2 , . . . , n ;   j = 1 , 2 , . . . , m H ( Y ∣ X ) = ∑ i = 1 n p i H ( Y ∣ X = x i ) P(X=x_i,Y=y_i)=p_{ij} \ \ \ i=1,2,...,n;\ j=1,2,...,m\\ H(Y|X)=\sum\limits_{i=1}^np_iH(Y|X=x_i) P(X=xi,Y=yi)=pij   i=1,2,...,n; j=1,2,...,mH(YX)=i=1npiH(YX=xi)
    H ( Y ∣ X ) H(Y|X) H(YX)表示随机变量X给定条件下随机变量Y的条件熵,换句话说,为X给定条件下Y的条件概率分布的熵对X的数学期望。
    当熵和条件熵中的概率由数据统计(极大似然估计)得到,则对应称为经验熵和经验条件熵。
  • 信息增益:集合D的经验熵H(D)与特征A在给定条件下D的经验条件熵H(D|A)之差,称为信息增益g(D,A)
    g ( D , A ) = H ( D ) − H ( D ∣ A ) g(D,A)=H(D)-H(D|A) g(D,A)=H(D)H(DA)
    该值表示由于特征A使得对数据集D的分类的不确定性减少的程度。信息增益越大,表示该特征对不确定性减少的程度越大,使得分类更偏向稳定。

5.2.2 信息增益比

信息增益作为划分时,为了尽可能降低不确定性,会出现偏向于选择取值较多的特征的问题,为了校正该问题,引入了信息增益比

  • 信息增益比:信息增益 g ( D , A ) g(D,A) g(D,A)与训练数据集D关于特征A的值的熵 H A ( D ) H_A(D) HA(D)d的比值为信息增益比 g R ( D , A ) g_R(D,A) gR(D,A)
    g R ( D , A ) = g ( D , A ) H A ( D ) H A ( D ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ l o g 2 ∣ D i ∣ ∣ D ∣     n 为 A 的 特 征 取 值 个 数 g_R(D,A)=\frac{g(D,A)}{H_A(D)}\\ H_A(D)=-\sum\limits_{i=1}^n\frac{|D_i|}{|D|}log_2\frac{|D_i|}{|D|} \ \ \ n为A的特征取值个数 gR(D,A)=HA(D)g(D,A)HA(D)=i=1nDDilog2DDi   nA

python代码实现例题:信息增益与信息增益比

import numpy as np
import math
#直接更改x,y即可
x = [[1, 0, 0, 1],
     [0, 1, 1, 1],
     [0, 0, 1, 0]]
y = [0, 0, 1]

feature_num = np.shape(x)[1]
y_len = len(y)

feature = np.array(x)


for i in range(feature_num):
    _feature = feature[:, i]
    temp_condition_ent = 0
    temp_ent_i = 0
    HA_D = 0
    print(_feature)
    for j in set(_feature):
        D_i = _feature.tolist().count(j)
        temp_ent = 0
        for k in set(y):
            temp_ent += -(y.count(k) / y_len) * math.log(y.count(k) / y_len)#H(D)
            D_ik = 0
            for index in range(len(y)):
                if y[index] == k and _feature[index] == j:
                    D_ik = D_ik + 1
            if D_ik != 0:
                temp_ent_i += -(D_ik / D_i) * math.log(D_ik / D_i)
            else:
                temp_ent_i = 0
        temp_condition_ent += (D_i / y_len) * temp_ent_i#H(D|A)
        conditon_ent = temp_ent - temp_condition_ent#g(D|A)
        HA_D += -(D_i / y_len) * math.log(D_i / y_len)#H_A(D)
    conditon_ent_ratio = conditon_ent / HA_D #g_R(D,A)
    print(conditon_ent)
    print(conditon_ent_ratio)

5.3 决策树的生成

5.3.1 ID3算法(python实现)

ID3算法的核心是决策树的各个节点上应用信息增益准则选择特征,递归的构建决策树,直到所有特征信息的信息增益均很小或没有特征选择位置。
算法5.2 ID3算法
输入:训练数据集D, 特征集A的阈值 ϵ \epsilon ϵ
输出:决策树T

  1. 若D中所有的实例属于同一类 C k C_k Ck,则T为单节点树,并将类 C k C_k Ck作为该节点的类标记,返回T;
  2. A = ∅ A=\varnothing A=,则T为单节点树,并将D中实例数最大的类 C k C_k Ck作为该节点的类标记,返回T;
  3. 否则,计算A中各特征对D的信息增益,选择信息增益最大的特征 A g A_g Ag
  4. 如果 A g A_g Ag的信息增益小于阈值 ϵ \epsilon ϵ,则置T为单节点树,并将D中实例数最大的类 C k C_k Ck作为该节点的类标记,返回T;
  5. 否则, A g A_g Ag的每一可能值 a i a_i ai,依照, A g = a i A_g=a_i Ag=ai将D分割为若干非空子集 D i D_i Di,将 D i D_i Di中实例数最大的类作为标记,构建子节点,由结点及其子节点构成树T,返回T;
  6. 对第i个子节点,以 D i D_i Di为训练集,以 A − { A g } A-\{A_g\} A{ Ag}为特征集,递归地调用步(1)到(5),得到子树 T i T_i Ti,返回 T i T_i Ti

python实现ID3算法(参考机器学习实战)

from math import log
# 计算信息熵
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 = shannonEnt - prob * log(prob, 2)
    return shannonEnt


# 划分数据集,axis:按第几个属性划分,value:要返回的子集对应的属性值
def splitDataSet(dataSet, axis, value):
    retDataSet = []
    featVec = []
    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

# 通过排序返回出现次数最多的类别
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]


# 递归构建决策树
def createTree(dataSet, labels):
    classList = [example[-1] for example in dataSet]  # 类别向量
    if classList.count(classList[0]) == len(classList):  # 如果只有一个类别,返回
        return classList[
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值