機(jī)器學(xué)習(xí): 決策樹

一. 背景

1. 適合決策樹應(yīng)用的三個條件

  • 訓(xùn)練數(shù)據(jù)記錄形式是attr-value pairs
  • 數(shù)據(jù)質(zhì)量: 數(shù)據(jù)可能可能有缺失的值, 有噪音
  • 離散型: 目標(biāo)函數(shù)y, 以及特征屬性字段都是離散類型; 如果是數(shù)值型變量, 也可以轉(zhuǎn)化成分類變量

2. 實際應(yīng)用

決策樹生成的if-then規(guī)則容易被人理解, 是一種非常清晰明了的知識. 很多情況下被用來做expert system. 很典型的一個例子是醫(yī)學(xué)上的診斷: 依據(jù)患者的p個癥狀, 給出其屬于哪個類型病癥(離散型)的答案.

3. 算法分類

ID3, 最早的實用算法.
當(dāng)下最常用的: C4.5, C5.0

二. 決策樹的基本

1. 樹的結(jié)構(gòu)

葉子層, 規(guī)則的結(jié)論; 內(nèi)層, 代表一個判斷結(jié)點.
順著一條鏈路下來是conjunction(&&合取關(guān)系), 而同層次之間是disjunction(||析取關(guān)系)的關(guān)系

example of a decision tree

2. 注意事項

必須把屬性字段收集好, 如果缺失了關(guān)鍵字段, 可能導(dǎo)致做不出一棵比較實用的決策樹.
同樣一批數(shù)據(jù), 可能有不同的正確的決策樹.

同一批數(shù)據(jù)生成的決策樹可能不是唯一的

奧卡姆剃刀: 簡單的樹更好. 這是因為簡單的樹, 更能抓住一些容易泛化的關(guān)鍵屬性, 通用能力更好, 實用性比較好.

3. 結(jié)點分裂算法

1 A = the best decision attr for next node  //tricky part, how to get the best attr? use entropy!!
2 Assign A as decision attr for node
3 For each value of A, create new descendant of node
4 sorting traninng example to leaf nodes
5 if trainnning examples perfectly classified:  //all records in a node are in the same category
        stop
else:
        iterate over new leaf nodes

三. ID3: 使用信息增益info gain分裂結(jié)點

1. 定義

info gain: how well a given attr separates the training examples according to their target classfication
entropy: purty of a Node, 取值總是正數(shù), 越高代表混亂度越大.
Ent(x) = - Σ pi log pi
note: 可以觀察到, pi∈[0, 1], 因此log(pi) <= 0, 所以必須在Σ前面加上負(fù)號, 把取值變成正.

2. 如何計算信息熵

我們找信息增益最大(使得信息熵下降最大的)屬性字段.
某個字段的信息增益 = 沒選這個字段前的信息熵(baseEntropy) - 選了之后的信息熵(newEntropy)

如何計算信息熵Entropy
#計算InfoGain的過程

S = [9+, 5-],  //S: Sample Set
Value(Wind) = { Weak, Strong }  //Unique value set of attribute 'Wind'
Sweak = [6+, 2-]   //Samples belongs to 'weak'
Sstrong = [3+, 3-]  //Samples belongs to 'strong'

Gain(S;A) = Entropy(S)-(8/14) Entropy(Sweak )-(6/14)Entropy(SStrong )  //記得要寫8/14, 6/14, 這代表的是每個部分的weight. 所以, 第一個weight是依據(jù)結(jié)點的UniqueValue
=[ -(9/14)log(9/14) - (5/14)log(5/14) ] - { (8/14)[ -(6/8)log(6/8) - (2/8)log(2/8) ] }  - { (3/6)[ -(3/6)log(3/6) - (3/6)log(3/6) ] }
= 0.940 – (8/14)0.811 – (6/14)1.00
= 0.048  
//weight ? [ -p1?log(p1) - p2?log(p2) ]   第二個p1, p2等值, 是依據(jù)cate類在本結(jié)點樣本(Sweak比如)上的占比

Python代碼

def calcShannonEntropy(dataset):
    """Calcuate Shannon Entropy value for a list-form dataset
    :param dataset: a list of vectors, with vec[-1] as each 's category
    note: cate = category
    """
    num = len(dataset)
    cateCount = {}
    for vec in dataset:
        curCate = vec[-1]
        if curCate not in cateCount.keys():
            cateCount[curCate] = 0  #create a new entry
        cateCount[curCate] += 1
    entropy = 0.0
    for key in cateCount.keys():
        prob = cateCount[key]/num
        entropy -= prob * log(prob,2)
    return entropy

3. 如何分裂結(jié)點

分裂結(jié)點的時候, 我們要做的事, 就是選取出那個使得InfoGain最大, 換句話說使得newEntropy最小的字段bestFeatureName

def splitDataset(dataset, axis, value):
    """Split a dataset by a selected feature. 
    This will delete the feature in the returnDataset.
    :param dataset: a list of vectors. Each vector is also a list.
    :param axis: a chosen feature to split.
    :param value: the chosen value for return dataset. 
    vector with other value will not be in the returnDataset
    """
    retDataset = [];
    for vec in dataset:
        if vec[axis]==value:
            retVec = vec[:axis]
            retVec.extend(vec[axis+1:])  #extend a list with another list
            retDataset.append(retVec)
    return retDataset  #returnDataset

#選取出infoGain最大的feature
def chooseBestSplitFeature(dataset):
    p = len(dataset[0])-1  #number of properties
    minEntropy = calcShannonEntropy(dataset)
    bestFeature = -99
    for i in range(p):  #compute each feature's result entropy
        feaList = [vec[i] for vec in dataset]  #tricky! get a whole column
        uniqueFeaSet = set(feaList)
        newEntropy = 0.0
        for value in uniqueFeaSet:
            aDataset = splitDataset(dataset, i, value)
            prob = len(aDataset)/len(dataset)
            newEntropy += prob*calcShannonEntropy(aDataset)  #別忘了要乘上prob
        if newEntropy < minEntropy: 
            minEntropy = newEntropy
            bestFeature = i
    if bestFeature == -99:
        print('bestFeature not chosen!!!')
    return bestFeature  #返回feature的index, 比如2

4. ID3算法偽代碼與實現(xiàn)

偽代碼

Python

#投票法得出某個葉子節(jié)點的最終category
def getMajority(classList):
    '''input: a list of class of this node, typically a leaf'''
    classCount = {}
    for vote in classList:  #class關(guān)鍵字得替換成vote, 因為python保留了這個關(guān)鍵字
        if vote not in classCount: classCount[vote] = 0
        classCount[vote] += 1
    aList = list(classCount.items())
    sortedClassCount = sorted(aList, key=lambda x:x[1], reverse=True) #key=!
    return sortedClassCount[0][0]

#給定list類型的dataset和feats, 創(chuàng)建一棵DecisionTree
def createTree(dataset, feats):
    localfeats = list(feats)
    classList = [row[-1] for row in dataset]
    if classList.count(classList[0])==len(classList):
        return classList[0]  #return a label as it reaches purity
    if len(dataset[0])==1:  #no feature left
        return getMajority(classList)
    #chooseFeature
    bestFeat = chooseBestSplitFeature(dataset)
    bestFeatKey = localfeats[bestFeat]
    del(localfeats[bestFeat])  #delete bestFeat from feats
    print('bestFeatureName:',bestFeatKey)
    #save the tree
    aTree = {bestFeatKey:{}}
    #split, create tree for each childnode
    uniqueVals = set([row[bestFeat] for row in dataset])
    for val in uniqueVals:
        subFeats = localfeats[:]
        childDataset = splitDataset(dataset, bestFeat, val)
        aTree[bestFeatKey][val] = createTree(childDataset, subFeats)
    return aTree

4. 從模型空間的角度來評價ID3算法

Hypo space is complete: target function surely in there. 模型假設(shè)的空間是完整的, 因此目標(biāo)函數(shù)(函數(shù)和模型在這里是同義詞)肯定在里面.
Robust to noisy data: statistically based search choices. 統(tǒng)計方法, 因此對噪聲抵御能力較強(qiáng)
No back tracking: local minima. 沒有回朔的手段, 因此可能陷入局部最優(yōu)
inductive bias: the shorter, the better. 喜歡最短的決策樹路徑, 這個是出于實用的考量, 但是卻不一定能得到最"精準(zhǔn)"的決策樹.

note: Restriction Biases & Preferences Biases
Preference bias is more desirable than Restriction biases. Restriction Biases直接把目標(biāo)函數(shù)給排除在了模型空間(Hypothesis Space)之外, 而PreferenceBias是算法使用者的一種傾向性, 比如在決策樹中, 算法使用者傾向使用短一些的決策樹, 這樣可以避免過擬合, 同時也容易理解一些.
一般我們認(rèn)為保留選擇給算法使用者是比較好的.

5. 數(shù)據(jù)的預(yù)先處理

1. 離散化方法

無監(jiān)督(用的多): 等長(從0~100劃分成5個bin), 定數(shù)量(每五個一類)
有監(jiān)督: 人為地, 借助標(biāo)簽地分開數(shù)據(jù). 比如看到45歲前沒什么得心臟病, 45歲后很多人得了, 人為地設(shè)定為分為"年輕人", "老年人"兩段.

2. 數(shù)據(jù)的缺失處理

離散型: 選取最頻繁出現(xiàn)的值(眾數(shù))來代替, 或者寫上缺失, 或者干脆刪除這個屬性(如果缺的太厲害)

6. 過擬合

解決辦法: prun 剪枝
tree size = 一個凸起的函數(shù). 要試圖接近最好的點

forward pruning

Orange框架中的規(guī)則: (Orange是一個實現(xiàn)了決策樹的框架)
如果結(jié)點上只有五個example就停止
如果發(fā)現(xiàn)這個結(jié)點有10個樣例, 有至少7個都已經(jīng)是一類(+/-), 那么可以停了
如果分支下去的兩個葉子中, 有一個只有一個或者兩個例子, 那么表示太具體了, 應(yīng)該剪掉葉子

backward pruning

原理和forward類似, 但是會更好用一些.

三. 使用信息增益率改進(jìn): c4.5算法

1. ID3算法存在的嚴(yán)重問題: 特征取值越多越容易被選取

極端的例子是用戶id, date這種取值極其多的屬性, 這樣屬性的每個獨特取值下, 都只有一個y的類別.
這樣, id, date這種字段的熵就等于0. 因此, 決策樹傾向于直接選取這些取值多的字段作為分裂結(jié)點.
而這樣在實際業(yè)務(wù)中幾乎沒有用的.

2. InfoGain解決特征取值過多問題

C4.5引入了一個SplitInfo的分母來降低取值多的字段的InfoGain.
已知, InfoGain = Ent(S) - Ent(S ; A)
當(dāng)遇到取值很多的字段的時候, Ent(S; A)急劇下降, 趨近于0. 那么, 我們可以對InfoGain整個值進(jìn)行縮小, 來緩解這種問題.
我們選用的是SplitInfo(S, A) = –Σpm?logpm, 其中pm = 字段取某個獨特值的時候, 所擁有的樣本數(shù) ÷ 總的樣本數(shù)(到達(dá)這個分裂結(jié)點的樣本數(shù))

比如Temp = {cold: 5, normal: 10, hot: 8}
SplitInfo = -5/23?lg5/23 - 10/23?lg10/23 - 8/23?lg8/23
顯然, 我們可以看出, 如果一個字段屬性下, 獨特的取值越多的話, 它的熵SplitInfo的值會越大. 由于SplitInfo被放在了分母的位置, 因此獨特取值越多的字段, 會分到一個越小的權(quán)重.

GainRatio(S, A) = Gain(S, A) / SplitInfo(S, A)

計算GainRatio

3. C4.5算法偽代碼

1 Check for the above base cases. //邊界條件檢查
2 For each attribute a, find the normalized information gain ratio from splitting on a.
3 Let a_best be the attribute with the highest normalized information gain.
4 Create a decision node that splits on a_best.
5 Recur on the sublists obtained by splitting on a_best, and add those nodes as children of node.

四. 最后: 決策樹的評價

評價: 算法原理? 什么時候用? 優(yōu)缺點?

1. 優(yōu)點

健壯性: 統(tǒng)計方法決定了決策樹抗噪聲.
結(jié)果容易被理解: 在醫(yī)療等領(lǐng)域應(yīng)用十分適合, 因為我們需要理解原因.

決策樹的這些優(yōu)點決定了它是一個簡單易用的機(jī)器學(xué)習(xí)方法.

2. 缺點

如果使用C4.5算法, 克服了某個特征屬性下獨特取值過多的問題后,
決策樹模型還是可能存在問題:
no backtracking: local optimal solution not global optimal solution 即無法回朔, 可能無法得到全局最優(yōu)

3. overall

  • practical 決策樹是一個簡單又實用的機(jī)器學(xué)習(xí)方法
  • overfitting problem: 是做決策樹的時候需要解決的問題;
  • id3 searches the whole tree with inductive bias for smaller tree "id3"算法存在著對較小決策樹的偏好.
  • 由于決策樹應(yīng)用很多, 因此其的實用算法中會有很多很多的改進(jìn)變種.

遺留一個問題供思考

如果樹的結(jié)點順序的不同, 結(jié)果會有不同嗎?

參考資料

信息增益與信息增益率詳解
c4.5為什么使用信息增益比來選擇特征?
<機(jī)器學(xué)習(xí)實戰(zhàn)> page42

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市惑朦,隨后出現(xiàn)的幾起案子兽泄,更是在濱河造成了極大的恐慌,老刑警劉巖漾月,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件病梢,死亡現(xiàn)場離奇詭異,居然都是意外死亡梁肿,警方通過查閱死者的電腦和手機(jī)蜓陌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吩蔑,“玉大人钮热,你說我怎么就攤上這事≈蚍遥” “怎么了隧期?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赘娄。 經(jīng)常有香客問我仆潮,道長,這世上最難降的妖魔是什么遣臼? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任性置,我火速辦了婚禮,結(jié)果婚禮上揍堰,老公的妹妹穿的比我還像新娘蚌讼。我一直安慰自己,他們只是感情好个榕,可當(dāng)我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布篡石。 她就那樣靜靜地躺著,像睡著了一般西采。 火紅的嫁衣襯著肌膚如雪凰萨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機(jī)與錄音胖眷,去河邊找鬼武通。 笑死,一個胖子當(dāng)著我的面吹牛珊搀,可吹牛的內(nèi)容都是我干的冶忱。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼境析,長吁一口氣:“原來是場噩夢啊……” “哼囚枪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起劳淆,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤链沼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沛鸵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體括勺,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年曲掰,在試婚紗的時候發(fā)現(xiàn)自己被綠了疾捍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡栏妖,死狀恐怖拾氓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情底哥,我是刑警寧澤咙鞍,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站趾徽,受9級特大地震影響续滋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜孵奶,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一疲酌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧了袁,春花似錦朗恳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至崭庸,卻和暖如春怀浆,著一層夾襖步出監(jiān)牢的瞬間谊囚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工执赡, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留镰踏,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓沙合,卻偏偏與公主長得像奠伪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子首懈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容