【決策樹DT】 算法原理 公式推導 python編程實現

1.信息增益

 

1.1 信息熵

        在信息論中,信息熵度量樣本集合純度是最常用的一種指標,信息熵用來描述信源的不確定度。例如:

A=太陽從東方升起      
B=太陽從西方升起

      對於句子A,確定度很高,基本爲必然事件。其信息熵較低,所含的信息量很小。

      對於句子B,不確定性特別高,基本不可能發生,所以其信息熵很高,所含信息量很大。

      需要注意的是,在自然語言處理中:

1.落霞與孤鶩齊飛,秋水共長天一色。 
2.落日下的晚霞與孤獨的大雁一同飛翔,晚秋的江水和深遠的天空連成一片

       按照信息熵的計算,第二句比第一句的信息熵要高1倍以上,你會覺得第二句比第一句水平要高,信息量更大麼?在自然語言處理中出現較大的信息熵,只表示可能出現的語言字符較多,並不意味着你可以從中得到更多的信息。

 

信息熵公式:

Ent(D)=-\sum_{1}^{m}plog(p)

1.2 信息增益

 

是否愛學習 是否天天打遊戲 是否沉迷女色 是否是優秀學生
愛學習 不打遊戲 沉迷女色
愛學習 打遊戲 不沉迷女色
不愛學習 打遊戲 沉迷女色
不愛學習 打遊戲 不沉迷女色

        我們用愛學習,打遊戲,沉迷女色來對數據集D(是否是優秀學生)進行決策。我們可以通過上式計算出數據集D的信息熵。首先,計算是否是優秀學生的信息熵:

Ent(D)=-(\tfrac{2}{4}log(\tfrac{2}{4})+\tfrac{2}{4}log(\tfrac{2}{4})){\color{Green} }=0.6931471805599453

在考慮屬性劃分時,我們有多個策略 如:

 

那麼我們應該怎麼選擇呢?這裏引入了信息增益的概念:

Gain(D,a)=Ent(D)-\sum_{v=1}^{V}|d|Ent(d)/D

d爲每個節點對應的屬性,比如打遊戲就分爲d1=打遊戲,d2=不打遊戲。一般而言,信息增益越大,則意味着使用此屬性來進行劃分所獲得的‘純度提升’越大。

讓我們來推到一下:

當a爲沉迷女色時:

D1爲沉迷女色,D2爲不沉迷女色

Ent(D1)=-(\tfrac{1}{2}log(\tfrac{1}{2})+\tfrac{1}{2}log(\tfrac{1}{2}))=0.6931471805599453

Ent(D2)=-(\tfrac{1}{2}log(\tfrac{1}{2})+\tfrac{1}{2}log(\tfrac{1}{2}))=0.6931471805599453

Gain(D,a)=Ent(D)-\sum_{v=1}^{V}|d|Ent(d)/D=0.6931471805599453-(\frac{2}{4}*0.6931471805599453+\frac{2}{4}*0.6931471805599453)=0

 

a爲打遊戲時:

D1爲天天打遊戲,D2爲不打遊戲

Ent(D1)=-\tfrac{1}{1}log\tfrac{1}{1}=0

Ent(D2)=-(\tfrac{1}{3}log(\tfrac{1}{3})+\tfrac{2}{3}log(\tfrac{2}{3})){\color{Green} }=0.6365141682948128 

Gain(D,a)=0.30103-(\frac{1}{4}*0+\frac{3}{4}*0.65312)=0.2157615543388356

 

當a爲愛學習時:

Ent(D1)=-\tfrac{2}{2}log\tfrac{2}{2}{\color{Green} }=0

Ent(D2)=-\tfrac{2}{2}log\tfrac{2}{2}{\color{Green} }=0

Gain(D,a)=0.6931471805599453-(\frac{2}{4}*0+\frac{2}{4}*0)=0.6931471805599453

從信息增益的結果我們發現愛學習對判斷一個學生是否優秀有很大提升,所以在決策樹中我們會首選愛學習作爲決策屬性。然後再對其餘屬性遞歸。

 

python代碼實現(未進行減枝策略):

# -*- coding: utf-8 -*-
"""
Created on Tue Sep  4 09:46:00 2018

@author: Adam
"""
import pandas as pd 
import numpy as np


dataSet = [['愛學習','不打遊戲','沉迷女色','是'],
           ['愛學習','打遊戲','不沉迷女色','是'],
           ['不愛學習','打遊戲','沉迷女色','否'],
           ['不愛學習','打遊戲','不沉迷女色','否']]

labels = ['是否愛學習','是否天天打遊戲','是否沉迷女色','是否是優秀學生']

data = pd.DataFrame(dataSet,columns=labels)
data = data.set_index('是否是優秀學生')


def Ent(data,col):
    number = len(data)
    label = data.index.value_counts()
    ent = 0
    for x in label:
        ent += -(x/number)*np.log2(x/number)
    return ent

indexEnt= Ent(data,data.index.name)

def GainEntTree(data,indexEnt):
    LabelData=list(data.index)
    if LabelData.count(LabelData[0])==len(LabelData):
        return LabelData[0]
    if len(data.columns)==0:
        return data.index.value_counts().sort_values(ascending=False).index[0]
    if len(data.columns)>0:
        GainEntlist=[]
        columnslist = data.columns
        lendata=len(data)
        for i in data.columns:
            Gain=[]
            ColValueCounts=data[i].value_counts()
            ColValueCountsindex=ColValueCounts.index
            ColValueCountsvalues=ColValueCounts.values
            for j in range(len(ColValueCountsindex)):
                D = data[data[i]==ColValueCountsindex[j]].index.value_counts()
                ent=sum([-(z/lendata)*np.log2(z/ColValueCountsvalues[j]) for z in D])
                Gain.append(ent)
            GainEntlist.append(sum(Gain))
        GainEntlist=[indexEnt-x for x in GainEntlist]
        x=dict(zip(columnslist,GainEntlist))
        top=sorted(x.items(),key=lambda item:item[1],reverse=True)[0][0]
        myTree={top:{}}
        for value in set(data[top]):
            newdata=data[data[top]==value].drop(top,axis=1)
            myTree[top][value]=GainEntTree(newdata,Ent(newdata,newdata.index.name))
        return myTree

GainEntTree(data,indexEnt)            
         






     

輸出爲

In [176]: GainEntTree(data,indexEnt)
Out[176]: {'是否愛學習': {'不愛學習': '否', '愛學習': '是'}}

用周志華老師機器學習書中的西瓜數據集檢查一下

dataSet = [['青綠','蜷縮','濁響','清晰','凹陷','硬滑','是'],
           ['烏黑','蜷縮','沉悶','清晰','凹陷','硬滑','是'],
           ['烏黑','蜷縮','濁響','清晰','凹陷','硬滑','是'],
           ['青綠','蜷縮','沉悶','清晰','凹陷','硬滑','是'],
           ['淺白','蜷縮','濁響','清晰','凹陷','硬滑','是'],
           ['青綠','稍蜷','濁響','清晰','稍凹','軟粘','是'],
           ['烏黑','稍蜷','濁響','稍糊','稍凹','軟粘','是'],
           ['烏黑','稍蜷','濁響','清晰','稍凹','硬滑','是'],
           ['烏黑','稍蜷','沉悶','稍糊','稍凹','硬滑','否'],
           ['青綠','硬挺','清脆','清晰','平坦','軟粘','否'],
           ['淺白','硬挺','清脆','模糊','平坦','硬滑','否'],
           ['淺白','蜷縮','濁響','模糊','平坦','軟粘','否'],
           ['青綠','稍蜷','濁響','稍糊','凹陷','硬滑','否'],
           ['淺白','稍蜷','沉悶','稍糊','凹陷','硬滑','否'],
           ['烏黑','稍蜷','濁響','清晰','稍凹','軟粘','否'],
           ['淺白','蜷縮','濁響','模糊','平坦','硬滑','否'],
           ['青綠','蜷縮','沉悶','稍糊','稍凹','硬滑','否']]

labels = ['色澤','根蒂','敲聲','紋理','臍部','觸感','好瓜']

第一輪信息增益:

[('紋理', 0.3805918973682686),
 ('臍部', 0.28915878284167895), 
('根蒂', 0.14267495956679277), 
('敲聲', 0.14078143361499607),
('色澤', 0.10812516526536531), 
('觸感',0.006046489176565695)]

信息增益與決策結果與書中數據吻合。

In [18]:GainEntTree(data,indexEnt)
Out[18]: 
{'紋理': {'模糊': '否','清晰': {'根蒂': {'硬挺': '否','稍蜷': {'色澤': {'烏黑': {'觸感': {'硬滑': '是', '軟粘': '否'}}, '青綠': '是'}},'蜷縮': '是'}},'稍糊': {'觸感': {'硬滑': '否', '軟粘': '是'}}}}

打賞一下作者:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章