Decision Tree

I I I k n o w know know n o t h i n g nothing nothing b u t but but m y my my i g n o r a n c e . ignorance. ignorance.

基本流程

在这里插入图片描述

注意:

  • 第二种返回情况,是在利用当前节点的后验分布
  • 第三种返回情况,是把父节点的样本分布作为当前节点的先验分布

e x a m p l e example example l i k e like like t h i s this this:

  • 第一种

样本的分类都是 1,所以不需要在进行属性划分了,直接将类别标记为 1。

年龄性别Y
181
191
  • 第二种

样本中属性年龄和性别都是一样的,而 类别 0 出现最多,所以类别应该标记为 0

年龄性别Y
181
180
180
  • 第三种

按性别对样本进行划分,则会出现数据集 D v ( 性 别 为 女 ) Dv(性别为女) Dv() 为空,分类标记为 1(因为 类别 1 最多)

年龄性别Y
181
191
190

划分选择

决策树学习的关键是第八行,即如何选择最优划分属性。随着划分过程不断进行,我们希望决策树的分支结点所包含的样本尽可能属于同一类别,即结点的“纯度”越来越高。

信息增益(ID3决策树)

信息熵 ( i n f o r m a t i o n (information (information e n t r o p y ) entropy) entropy) 是度量样本集合纯度最常用的一种指标。假定当前样本集合 D D D中第 k k k类样本所占的比例为 p k ( k = 1 , 2 … , ∣ γ ∣ ) p_k(k=1,2…,|\gamma|) pk(k=12γ),则 D D D信息熵 定义为:

E n t ( D ) = − ∑ k − 1 ∣ γ ∣ p k l o g 2 p k E n t ( D ) 越 小 , D 的 纯 度 越 高 Ent(D) = -\sum_{k-1}^{|\gamma|}p_klog_2p_k\\ Ent(D)越小,D 的纯度越高 Ent(D)=k1γpklog2pkEnt(D)D

假定离散属性 a a a V V V 个可能的取值 a l , a 2 , . . , a V {a^l,a^2,..,a^V} al,a2,..aV,若使用 a a a 来对样本集D进行划分,则会产生 V V V 个分支结点,其中第 v v v 个分支结点包含了 D D D 中所有在属性 a a a 上取值为 a v a^v av 的样本,记为 D v D^v Dv。则把属性 a a a 对样本集 D D D 进行划分所获得的 信息增益 定义为:

G a i n ( D , a ) = E n t ( D ) − ∑ v = 1 V ∣ D v ∣ ∣ D ∣ E n t ( D v ) Gain(D,a)=Ent(D)-\sum_{v=1}^{V}\frac{|D^v|}{|D|}Ent(D^v) Gain(D,a)=Ent(D)v=1VDDvEnt(Dv)

一般来说,信息增益越大,我们使用 a a a 来进行划分所获得的纯度提升越大。所以决策树的最优属性划分可以是:

a ∗ = a r g m a x G a i n ( D , a ) a ∈ A a* = arg maxGain(D,a)\\ a\in A a=argmaxGain(D,a)aA

著名的 I D 3 ID3 ID3 决策树学习算法就是以信息增益为准则来选择划分属性的。

增益率(C4.5决策树)

使用增益率选择最优划分 是为了减少信息增益准则对取值数码较多的属性偏好可能带来的不利影响。

增益率 定义为:

G a i n _ r a t i o ( D , a ) = G a i n ( D , a ) I V ( a ) I V ( a ) = − ∑ v = 1 V ∣ D v ∣ D l o g 2 ∣ D v ∣ D I V ( a ) 称 为 属 性 a 的 固 有 值 Gain\_ratio(D,a) = \frac{Gain(D,a)}{IV(a)}\\ IV(a)=-\sum_{v=1}^{V}\frac{|D^v|}{D}log_2\frac{|D^v|}{D}\\ IV(a)称为 属性a的固有值 Gain_ratio(D,a)=IV(a)Gain(D,a)IV(a)=v=1VDDvlog2DDvIV(a)a

属性 a a a 可能取值数目越多(V越大),则 I V ( a ) IV(a) IV(a) 的值通常也会越大,增益率减小。显然,如果直接使用增益率最大来选择最优属性的话,就会产生对可取值数目较少的属性偏好带来的影响。因此,需要使用一个启发式:先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的

基尼指数(CART决策树)

CART 决策树使用 基尼指数 G i n i i n d e x Gini index Giniindex),来选择划分属性。数据集 D D D 的纯度可用基尼值来度量:
G i n i ( D ) = ∑ k = 1 ∣ γ ∣ ∑ k ′ ≠ k p k p k ′ = 1 − ∑ k = 1 ∣ γ ∣ p k 2 Gini(D)=\sum_{k=1}^{|\gamma|}\sum_{k'\neq k}p_kp_k'\\ =1-\sum_{k=1}^{|\gamma|}p_k^2 Gini(D)=k=1γk=kpkpk=1k=1γpk2

CART 是 Classification and Regression Tree 的简称,可用于分类和回归任务

G i n i ( D ) Gini(D) Gini(D) 反映了从数据集 D D D 中随机抽取两个样本,其类别标记不一致的概率, G i n i ( D ) Gini(D) Gini(D) 越小,则数据集 D 的纯度越高。
属性 a a a 的基尼指数定义为:

G i n i _ i n d e x ( D , a ) = ∑ v = 1 V ∣ D v ∣ ∣ D ∣ G i n i ( D v ) Gini\_index(D,a)=\sum_{v=1}^{V}\frac{|D^v|}{|D|}Gini(D^v) Gini_index(D,a)=v=1VDDvGini(Dv)

最优划分属性 a ∗ = a r g m i n G i n i _ i n d e x ( D , a ) a* = argminGini\_index(D,a) a=argminGini_index(D,a)



# 西瓜数据集
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use('ggplot')
%matplotlib inline
# 对中文的支持
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
df = pd.read_csv('watermelon.data')
df.head()
编号色泽根蒂敲声纹理脐部触感密度含糖率好瓜
01青绿蜷缩浊响清晰凹陷硬滑0.6970.460
12乌黑蜷缩沉闷清晰凹陷硬滑0.7740.376
23乌黑蜷缩浊响清晰凹陷硬滑0.6340.264
34青绿蜷缩沉闷清晰凹陷硬滑0.6080.318
45浅白蜷缩浊响清晰凹陷硬滑0.5560.215
# 求信息熵
def ent(data,a):
    info_ent = {}  # 信息熵
    root = '好瓜'
    # 求根节点信息熵
#     if a==root:
    if a ==root:
        pi = data[root].value_counts()/len(data)
        return np.sum(-pi*np.log2(pi))
    
    # 子节点信息熵
    a_val = data[a].value_counts()  # 属性 a = {D1,D2,..,Dv}
    a_index = a_val.index           # example-> ['乌黑', '青绿', '浅白']
    
    for d in a_index:
        # d = '乌黑'...
        temp_data = data[data[a]==d]
        pi = temp_data[root].value_counts()/len(temp_data)
        info_ent[d] =  np.sum(-pi*np.log2(pi))
    return info_ent

# 求信息增益
def gain(data,a):
    info_gain = ent(data,'好瓜') # 信息增益
#     print("根节点信息熵:%f"%info_gain)
    info_ent = ent(data,a)
    Pd = data[a].value_counts()/len(data[a])         # Dv/D
    for k,v in info_ent.items():
        info_gain -= Pd[k]*v
    return info_gain

# 求属性 a 的固有值
def iv(dt,a):
    filt = dt[a].value_counts()
    iv_a = 0
    for i in filt:
        iv_a -= np.abs(i/filt.sum())*np.log2(i/filt.sum())
    
    return iv_a

# 增益率
def grain_ratio(dt,a):
    iv_a = iv(dt,a)
    gain_a = gain(dt,a)
    gr = gain_a/iv_a
#     print(a+"的增益率:%f"%gr)
    return gr

# 求 数据集 D 的基尼值
def gini(dt):
    filt = dt.iloc[:,-1].value_counts()
    gini_d = 1
    for i in filt:
        gini_d -= (i/filt.sum()) **2
        
    return gini_d

# 属性 a 的基尼指数
def gini_index(dt,a):
    gd = 0
    a_val = attr[a]
    filt = dt[a].value_counts()

    for i in filt.index:
        Dv = dt[dt[a]==i]
        gd += (filt[i]/filt.sum())*gini(Dv)
        
    return gd

# 根据信最大息增益 从 A 中选择最优划分属性 【ID3 决策树】      
def get_gain_max_a(dt,index_A):
    gain_list = []
    for ad in index_A:
        gain_list.append(gain(dt,ad))
    
    gain_max = np.max(gain_list)
    arg = np.argmax(gain_list)
    
    # 最优属性
    best_a = index_A[arg]
    
    index_A.remove(best_a)
    return best_a,gain_max

# 根据增益率 选择最优划分属性 【C4.5决策树】
def get_gainrate_max_a(dt,index_A):
    gain_list = []
    for ad in index_A:
        gain_list.append(gain(dt,ad))
    
    # 平均信息增益
    mean_gain = np.mean(gain_list)
    
    gain_list = np.array(gain_list)
    np_index = np.array(index_A)
    
    args = np.where(gain_list>=mean_gain)
    
    # 高于平均信息增益的属性
    up_mean_a = np_index[args]
    
    # 求增益率
    gain_rate_list = [grain_ratio(dt,a) for a in up_mean_a]
    
    # 高于平均信息增益属性中的最大增益率
    max_gain_rate = np.max(gain_rate_list)

    # 下标
    arg = np.argmax(gain_rate_list)

    # 最优属性
    best_a = up_mean_a[arg]
    
    index_A.remove(best_a)
    
    return best_a,max_gain_rate

# 根据最小基尼指数选择最优划分属性 【CART 决策树】
def get_gini_min_a(dt,index_A):
    gini_list = []
    for ad in index_A:
        gini_list.append(gini_index(dt,ad))
    
    arg = np.argmin(gini_list)
    min_gini_index = np.min(gini_list)
    
    # 基尼指数最小的属性
    best_a = index_A[arg]
    index_A.remove(best_a)
    return best_a,min_gini_index
    

# 获取所有属性对应的可能取值:
def get_attr(dt):
    """
    return like this:
    {'色泽':{'青绿','浅白','乌黑']}...}
    """
    attr = {}
    col = dt.columns
    for c in col:
        attr[c]= set(dt[c])
    
    return attr

# 判断 D 中样本在 A 上取值是否相同
def check(dt):
    col = dt.columns[:-1]
    for i in col:
        if len(set(dt[i]))!=1:
            return False
        
    return True
        
# 基本决策树流程
def treeG(dt,A,attr):
    # 默认最后一行为标签
    Y = dt.iloc[:,-1].value_counts() #.index
    
    # 属性集 A = {a1,a2,..,ad}
    index_A = list(A)

    # 如果样本属于同一类别 C,则返回
    if len(Y)==1:
        # 将 节点标记为 类别 C
        print("好瓜:"+str(Y.index[0]))
        return '无需划分'
    # 如果 A 属性集为空或 D中样本在 A 上取值相同
    if len(index_A)==0 or check(dt):
        m = dt.iloc[:,-1].value_counts()
        geq = np.argmax(m) 
        print(geq)
        return '无法划分'
    
    # 从 A 中选择最优划分属性 即 求最大信息熵对应的属性 a*
    max_a,gain_max= get_gain_max_a(dt,index_A)             # id3 决策
#     max_a,gain_rate_max = get_gainrate_max_a(dt,index_A)   # C4.5 决策
#     max_a,gini_index_min = get_gini_min_a(dt,index_A)          # CART 决策
#     print(max_a,gain_max)

    # 根据属性 a* 分类数据集然后遍历 eg: a_v in ['清晰','稍糊','模糊']
    for a_v in attr[max_a]:
        Dv = dt[dt[max_a]==a_v][index_A+[Y.name]]
        print(max_a,gain_max,'--%s-->'%a_v)
        if len(Dv)==0:
            m = dt.iloc[:,-1].value_counts()
            geq = np.argmax(m) 
            print("好瓜:"+geq)
            return '不能划分'
        else:
            treeG(Dv,index_A,attr)
        
dt = df.iloc[:,[1,2,3,4,5,6,-1]]
A = list(df.columns[[1,2,3,4,5,6]])
Y = '好瓜'
dt
色泽根蒂敲声纹理脐部触感好瓜
0青绿蜷缩浊响清晰凹陷硬滑
1乌黑蜷缩沉闷清晰凹陷硬滑
2乌黑蜷缩浊响清晰凹陷硬滑
3青绿蜷缩沉闷清晰凹陷硬滑
4浅白蜷缩浊响清晰凹陷硬滑
5青绿稍蜷浊响清晰稍凹软粘
6乌黑稍蜷浊响稍糊稍凹软粘
7乌黑稍蜷浊响清晰稍凹硬滑
8乌黑稍蜷沉闷稍糊稍凹硬滑
9青绿硬挺清脆清晰平坦软粘
10浅白硬挺清脆模糊平坦硬滑
11浅白蜷缩浊响模糊平坦软粘
12青绿稍蜷浊响稍糊凹陷硬滑
13浅白稍蜷沉闷稍糊凹陷硬滑
14乌黑稍蜷浊响清晰稍凹软粘
15浅白蜷缩浊响模糊平坦硬滑
16青绿蜷缩沉闷稍糊稍凹硬滑
# ent(dt,'色泽')
attr = get_attr(dt)
treeG(dt,A,attr)
纹理 0.3805918973682686 --模糊-->
好瓜:否
纹理 0.3805918973682686 --清晰-->
根蒂 0.45810589515712374 --硬挺-->
好瓜:否
根蒂 0.45810589515712374 --蜷缩-->
好瓜:是
根蒂 0.45810589515712374 --稍蜷-->
色泽 0.2516291673878229 --青绿-->
好瓜:是
色泽 0.2516291673878229 --乌黑-->
触感 1.0 --软粘-->
好瓜:否
触感 1.0 --硬滑-->
好瓜:是
色泽 0.2516291673878229 --浅白-->
好瓜:是
纹理 0.3805918973682686 --稍糊-->
触感 0.7219280948873623 --软粘-->
好瓜:是
触感 0.7219280948873623 --硬滑-->
好瓜:否

根据信息增益生成的决策树如下:

在这里插入图片描述


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值