《统计学习方法》第五章: 决策树 读书笔记


一切为了数据挖掘的准备

5.决策树(decision tree)
  • 决策树是一种基本的分类与回归方法,本章只涉及分类问题
  • 通常有三个步骤:特征选择,决策树生成,决策树修剪
  • 决策树的内部结点表示一个特征或属性,叶结点表示一个类
  • 决策树可以表示给定特征条件下类的条件概率分布。
5.1特征选择标准

需要选取对训练数据具有分类能力的特征,提高决策树学习效率。选择准则通常是信息增益或信息增益比。

5.1.1 熵
  • 熵:对随机变量不确定性的度量。或表示随机变量的混乱、离散程度。
  • 表示:设Y是一个取有限个值的离散随机变量,概率分布为 P ( Y = y i ) = p i , i = 1 , 2 , ⋯   , K P(Y=y_i)=p_i, i=1,2,\cdots,K P(Y=yi)=pi,i=1,2,,K,则随机变量Y熵的定义为:
    H ( Y ) = − ∑ k = 1 K p i l o g p i H(Y)=-\sum_{k=1}^Kp_ilogp_i H(Y)=k=1Kpilogpi

通常对数以2为底或以e为底,这时熵的单位为比特或纳特。

  • 经验熵:由样本集T得到熵的极大似然估计
    H ( Y ) = − ∑ k = 1 K c k N l o g c k N H(Y)=-\sum_{k=1}^K\frac{c_k}{N}log\frac{c_k}{N} H(Y)=k=1KNcklogNck

其中 c k c_k ck为Y取值 y i y_i yi时的样本数;N为总样本数

  • 如果Y为二值变量, H ( Y ) = − [ p l o g p + ( 1 − p ) l o g ( 1 − p ) ] H(Y) = -[plogp+(1-p)log(1-p)] H(Y)=[plogp+(1p)log(1p)]
  • 当Y为二值变量,Y的取值越确定时,熵 H ( Y ) H(Y) H(Y)越小。例如p=0,或p=1时H(Y)=0,不确定性为0;当p=0.5时,H(Y)=1,不确定性最大。
5.1.2 条件熵
  • 条件熵H(Y|X)在已知随机变量X的条件下,随机变量Y的不确定性。即利用特征X将数据分组,随机变量Y的混乱程度

  • 表示:设随机变量X取值范围为 x 1 , x 2 , ⋯   , x n x_1,x_2,\cdots,x_n x1,x2,,xn,随机变量Y的取值范围为 y 1 , y 2 , ⋯   , y k y_1,y_2,\cdots,y_k y1,y2,,yk,条件熵定义为:
    H ( Y ∣ X ) = ∑ i = 1 n p i H ( Y ∣ X i ) = − ∑ i = 1 n p i ∑ j = 1 k p i j l o g p i j H(Y|X)=\sum_{i=1}^n p_iH(Y|X_i)=-\sum_{i=1}^np_i\sum_{j=1}^kp_{ij}logp_{ij} H(YX)=i=1npiH(YXi)=i=1npij=1kpijlogpij
    p i = P ( X = x i ) , p i j = P ( Y = y j ∣ X = x i ) = P ( Y = y j ∣ X = x i ) P ( X = x i ) p_i = P(X=x_i), p_{ij}=P(Y=y_j|X=x_i)=\frac{P(Y=y_j|X=x_i)}{P(X=x_i)} pi=P(X=xi),pij=P(Y=yjX=xi)=P(X=xi)P(Y=yjX=xi)

  • 经验条件熵:由样本集T进行条件熵的极大似然估计
    H ( Y ∣ X ) = − ∑ i = 1 n m i N ∑ k = 1 K m i k m i l o g m i k m i H(Y|X)=-\sum_{i=1}^n\frac{m_i}{N}\sum_{k=1}^K\frac{m_{ik}}{m_i}log\frac{m_{ik}}{m_i} H(YX)=i=1nNmik=1Kmimiklogmimik

m i m_i mi是X取值 x i x_i xi时的样本数,N是总样本数, m i k m_{ik} mik是X取值 x i x_i xi的样本中被分类为 y k y_k yk的样本数

5.1.3 信息增益
  • g ( D , A ) g(D,A) g(D,A):特征A对训练数据集D的信息增益.表示给定特征A后,将随机变量D的混乱程度降低了多少。

  • 表示:定义为集合D的经验熵 H ( D ) H(D) H(D)与特征A给定条件下D的经验条件熵之差
    g ( D , A ) = H ( D ) − H ( D ∣ A ) = − ∑ j = 1 k p j l o g p j + ∑ i = 1 n p i ∑ j = 1 k p i j l o g ( p i j ) g(D,A) = H(D) - H(D|A)= -\sum_{j=1}^kp_jlogp_j + \sum_{i=1}^np_i\sum_{j=1}^kp_{ij}log(p_{ij}) g(D,A)=H(D)H(DA)=j=1kpjlogpj+i=1npij=1kpijlog(pij)

  • 信息增益大的特征具有更强的分类性

5.1.4信息增益比
  • g R ( D , A ) g_R(D,A) gR(D,A):特征A对训练数据集D的信息增益比
  • 表示:
    g R ( D , A ) = g ( D , A ) H A ( D ) g_R(D,A) = \frac{g(D,A)}{H_A(D)} gR(D,A)=HA(D)g(D,A)
    H A ( D ) = − ∑ i = 1 n p i l o g p i = − ∑ i = 1 n m i N l o g ( m i N ) H_A(D) =- \sum_{i=1}^np_ilogp_i =- \sum_{i=1}^n\frac{m_i}{N}log(\frac{m_i}{N}) HA(D)=i=1npilogpi=i=1nNmilog(Nmi)
5.2决策树生成算法

决策树生成算法递归产生决策树,往往对训练数据集的分类准确,但泛化能力不强,容易过拟合。需要根据损失函数最小化进行剪枝,避免过拟合

5.2.1 ID3决策树生成算法

输入:训练数据集D,特征集A,阈值 ϵ \epsilon ϵ,输出:决策树

  • 1.如果D中所有实例属于同一类 C k C_k Ck,则T为单结点树,并将类 C k C_k Ck作为该点的类标记,返回T
  • 2.如果特征集A为空,T为单结点树,把D中实例数最大的类 C k C_k Ck作为该点的类标记,返回T
  • 4.否则计算A中各特征对D的信息增益,选择信息增益最大的特征 A g A_g Ag
  • 5.如果 A g A_g Ag对应的最大的信息增益小于阈值 ϵ \epsilon ϵ,T为单结点树,把D中实例数最大的类 C k C_k Ck作为该点的类标记,返回T(代表没有明显的特征可以将数据集分类)
  • 6.否则将数据集D按照特征 A g A_g Ag分割成若干个子集,将子集中中实例数最大的类 C k C_k Ck作为该点的类标记,构建子结点,从而形成根结点及子结点,返回T
  • 7.对第i个子结点,对该结点分割的子集,以 A − { A g } A-\{A_g\} A{Ag}为特征集(即还未被用于分类的特征),递归调用1-6步骤,得到子树 T i T_i Ti,返回子树
5.2.2C4.5生成算法

用信息增益比代替ID3中的信息增益,选择特征

5.3决策树的剪枝
  • 剪枝:将已生成的树进行简化,从已生成的树上裁掉一些子树或叶结点,并将其父结点作为新的叶结点。
5.3.1 损失函数

设数的叶结点个数 ∣ T ∣ |T| T,t是叶结点,该叶结点有 N t N_t Nt个样本点,其中k类的样本点有 N t k N_{tk} Ntk个, H t ( T ) H_t(T) Ht(T)是叶结点t上的经验熵, α \alpha α是参数,损失函数定义为:
C α ( T ) = ∑ t = 1 ∣ T ∣ N t H t ( T ) + α ∣ T ∣ C_\alpha(T) = \sum_{t=1}^{|T|}N_tH_t(T)+\alpha|T| Cα(T)=t=1TNtHt(T)+αT
H t ( T ) = − ∑ k N t k N t l o g N t k N t H_t(T)=-\sum_k\frac{N_{tk}}{N_t}log\frac{N_{tk}}{N_t} Ht(T)=kNtNtklogNtNtk
C ( T ) = − ∑ t = 1 ∣ T ∣ ∑ k N t k l o g N t k N t C(T) = -\sum_{t=1}^{|T|}\sum_kN_{tk}log\frac{N_{tk}}{N_t} C(T)=t=1TkNtklogNtNtk
C α ( T ) = C ( T ) + α ∣ T ∣ C_\alpha(T) = C(T) + \alpha|T| Cα(T)=C(T)+αT

  • ∣ T ∣ |T| T表示模型复杂度,较大的 α \alpha α促使选择较简单的模型,较小的 α \alpha α促使选择较复杂的模型
  • α \alpha α确定时,选择损失函数最小的子树。
5.3.2树的剪枝算法

输入:生成算法产生的整个树T,参数 α \alpha α;输出:修剪后的子树 T α T_\alpha Tα

  • 计算每个结点的经验熵
  • 递归的从树的叶结点向上回缩,计算损失函数,若损失函数降低,进行剪枝,将父结点变为新的叶结点。
  • 重复上一步骤,直至不能继续,得到损失函数最小的子树
5.4CART算法(对于分类树)
  • CART算法假设决策树是二叉树,每个结点特征取值为是/否,左分支为是,右分支为否。哪怕一个特征有3个以上取值,也只分为两部分,分为等于其中一个值、不等于这个值两部分。
5.4.1基尼指数
  • 基尼指数,表示集合D的不确定性
    G i n i ( p ) = ∑ k = 1 K p k ( 1 − p k ) = ∑ k = 1 K ∣ C k ∣ ∣ D ∣ ( 1 − ∣ C k ∣ ∣ D ∣ ) Gini(p) = \sum_{k=1}^Kp_k(1-p_k)=\sum_{k=1}^K\frac{|C_k|}{|D|}(1-\frac{|C_k|}{|D|}) Gini(p)=k=1Kpk(1pk)=k=1KDCk(1DCk)

  • 在特征A条件下,D的基尼指数:表示经A分割后集合D的不确定性
    G i n i ( D , A ) = ∑ i = 1 n ∣ D i ∣ ∣ D ∣ G i n i ( D i ) Gini(D,A) = \sum_{i=1}^n\frac{|D_i|}{|D|}Gini(D_i) Gini(D,A)=i=1nDDiGini(Di)

5.4.2CART生成算法

输入:训练数据集D,停止计算的条件(结点中的样本数小于预设阈值,或样本的基尼指数小于预定阈值,或没有更多特征);输出:CART决策树(为二叉决策树)。

  • 1.设训练数据集D,计算现有特征对该数据集的基尼指数。对于每个特征 A g A_g Ag,对其每个可能的取值 a i a_i ai,计算其基尼指数
  • 2.在所有可能的特征及所有可能的切分点中,选择基尼指数最小的特征及切分点,作为最优特征与最优切分点。根据此点(按照 A g = a , A g ≠ a A_g = a,A_g \neq a Ag=a,Ag=a)将数据集切分为两部分,构成两个子结点
  • 3.对两个子结点递归调用1,2,但需要在 A − { A g } A-\{A_g\} A{Ag}的特征中,选择所有的切分点进行基尼指数比较,选择基尼指数最小的切分点进行切分,直至满足停止条件。

5.5 几个离散程度指数的区别
方差

对于取值大小有意义的离散变量
D ( X ) = ∑ p i ( x i − X ‾ ) 2 D(X)=\sum p_i(x_i-\overline X)^2 D(X)=pi(xiX)2

对于取值大小无意义的离散变量,计算取值的混乱程度
H ( Y ) = − ∑ p i l o g p i H(Y) = -\sum p_ilogp_i H(Y)=pilogpi

基尼指数

对于取值大小无意义的离散变量,计算取值的混乱程度
G i n i ( p ) = ∑ p ( 1 − p ) Gini(p)=\sum p(1-p) Gini(p)=p(1p)

在二分类问题中,基尼指数 G i n i ( p ) Gini(p) Gini(p)和熵之半 1 2 H ( p ) \frac{1}{2}H(p) 21H(p)和分类误差率的关系。

  • 我对分类误差率的理解:假如取值0的概率p=0.3,猜测取值为1,猜错的概率(分类误差率)就是0.3;加入取值0的概率p=0.8,猜测取值为0,猜错的概率就是0.3.

分类误差率


5.6我的实现
import pandas as pd
from pandas import Series,DataFrame
import math
class DecissionTree:
    def __init__(self,X,Y,featureclass):
        self.data = DataFrame(X,columns = featureclass)
        self.data['yvalue'] = Y
        self.featureclass = featureclass
        self.tree = self.createTree(self.data)
    
    def createTree(self,data):
        """
        data的列为X的特征和Y分类构成,最终构成的树为一个字典,字典的外层key是特征class名称,
        value也是字典,key是这个特征取值,如果是叶节点,value是分类结果,如果是内部节点,
        value仍然是个字典,代表子树
        """
        #如果所有的实例同属一类
        if data['yvalue'].nunique() == 1:
            return data['yvalue'].unique()
        #如果特征集为空,即没有特征可以拿来分类,选择样本最多的y值
        if len(data.columns) == 1:
            return data['yvalue'].value_counts().sort_values(ascending=False).index[0]
        # 选择信息增益最大的特征进行分类
        bestfeature = self.chooseBestFeature(data)
        myTree = {bestfeature:{}}
        #按照选择的特征分类后,对分类的数据集递归调用函数
        for xvalue in data[bestfeature].unique():
        	#用剩余未被用于分类的特征数据生成子树
            subdata = data.drop([bestfeature],axis=1)
            subTree = self.createTree(subdata)
            myTree[bestfeature][xvalue] = subTree
        return myTree
    
    def predict(self,x):
        """
        输入x是一个列表,输出是一个类别
        """
        x = Series(x,index = self.featureclass)
        myTree = self.tree
        while type(myTree).__name__=='dict':
            for feature in myTree.keys():
                myTree = myTree[feature][x[feature]]
        return myTree
            
    
    def calcEntropy(self,data):
        """
        计算数据集的熵,熵 = -sum(plog(p)),输入为DataFrame,输出为float
        """
        ydata = data['yvalue'].value_counts()/len(data)
        entropy = ydata.apply(lambda x: -x*math.log(x,2)).sum()
        return entropy
    
    def chooseBestFeature(self,data):
        """
        计算A中各特征对数据的信息增益,选择信息增益最大的特征,
        信息增益: -sum plog(p) - sum px sum -pxylog pxy,
        """
        bestfeature = ''
        maxInfomationGain = 0.0
        # 数据集的熵
        entropy = self.calcEntropy(data)
        #计算每个特征的条件熵
        for feature in data.columns[:-1]:
            pfeature = data.loc[:,feature].value_counts()/len(data)
            conditionalEntropy = 0.0
            for xvalue in pfeature.index:
                conditionalEntropy += pfeature[xvalue]* self.calcEntropy(data[data.loc[:,feature]==xvalue])
            #信息增益
            infomationGain = entropy - conditionalEntropy
            if maxInfomationGain < infomationGain:
                maxInfomationGain = infomationGain
                bestfeature = feature
        #信息增益最大的特征
        return bestfeature

X = [['青年','否','否','一般'],['青年','否','否','好'],['青年','是','否','好'],['青年','是','是','一般'],['青年','否','否','一般']
    ,['中年','否','否','一般'],['中年','否','否','好'],['中年','是','是','好'],['中年','否','是','非常好'],['中年','否','是','非常好']
    ,['老年','否','是','非常好'],['老年','否','是','好'],['老年','是','否','好'],['老年','是','否','非常好'],['老年','否','否','一般']]
Y = ['否','否','是','是','否','否','否','是','是','是','是','是','是','是','否']
dt = DecissionTree(X,Y,['年龄','是有工作','是否有房子','信贷情况'])
x=['青年','否','是','一般']
dt.predict(x)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值