(轉)Decision Tree

Decision Tree:Analysishtml

 

你們有沒有玩過猜猜看(Twenty Questions)的遊戲?我在內心想一件物體,你能夠用一些問題來肯定我內心想的這個物體;如是否是植物?是否會飛?能游泳不?當你問完這些問題後,你就能獲得這個物體的特徵,而後猜出我內心想象的那個物體,看是否正確。算法

這個遊戲很簡單,可是蘊含的思想倒是質樸的。每一個問題都會將範圍減小,直到特徵顯現,內蘊的思想就是Decision Tree算法。斷定樹(Decision Tree)算法是機器學習中很重要的一種算法,有文章聲稱該算法在ML學習中最爲經常使用的算法,你不須要明白高深的知識就能明白算法的運行原理。app

 

Decision Tree包括如下幾個部分:dom

  • Root:根節點,Decision Tree使用了樹的概念,必然有Root屬性。
  • Decision Node:斷定節點,該節點的數據會繼續根據數據屬性繼續進行斷定。
  • Branch:從Decision Node迭代生成的子樹是子樹根節點的一個屬性判斷
  • End Node:也稱爲Leaf Node,該節點其實是作出決定的節點,對於樣本屬性的判斷到Leaf Node結束。 

Decision Tree分類:機器學習

Classification Tree:測試數據通過Classification Tree處理後,看結果歸屬於那個類別(Class)。性能

Regression Tree:若是測試數據的輸出是數值類型,能夠考慮使用Regression Tree。學習

CART(Classification And Regression Tree)s算法是對上面兩種算法的術語涵蓋。用來回歸的樹(Regression Tree)和用來分類的樹(classification Tree)具備必定的類似性,不過其不一樣之處在於決定分裂(Split)的過程。測試

使用某些技術(Ensemble Methods),能夠構建多個Decision Tree:大數據

Bagging Decision Tree:建立多個Decision Tree,經過替換訓練集合,獲得多個Decision Tree,最終獲得一致的結果。優化

Random Forest Classification Decision Tree:使用多個Decision Tree,提高分類的準確率。

Boosted Trees:可使用於迴歸(Regression)和分類(Classification)的問題。

Rotation Forest:Decision Tree生成是從訓練集合特徵屬性中隨機選取,使用PCA分析方法來構建Decision Tree。

 

Gini Impurity

該Gini度量是指隨機選擇集合中的元素,根據集合中label的分佈將該元素賦予分類,該元素分類錯誤的概率。Gini度量在CART算法中使用,其定義以下:

 

其中i爲label標籤,fi爲label爲i標籤的比例(Fraction)

 

Information Gain

這個是比較常見的信息度量,在Information Theory中常用,基於熵(entropy)的概念。在ID三、C4.五、C5.0中使用。其定義以下:

 

i爲label標籤,fi爲label標籤的比例,和上面的定義一致。Information Gain的定義以下:

 

Entropy和Information Gain的定義還會在後面章節裏用到,確保本身正確理解了Information Gain的定義。 本文最後會有個教程,幫助你們學習下Information Gain的概念。

 

Decision Tree的優勢和缺點:

1:易於理解和解釋,簡單解釋就能明白Decision Tree的模型和運行原理,對於結果也比較容易解釋。

2:數據預處理少,其它算法須要處理Data Normalization、Dummy Variable、Blank Value都須要進行預處理。

3:可以處理數值數據和分類數據,可以使用Decision Tree和Regression Tree就是例證。

4:使用白盒(White Box)模型,使用白盒模型可以在給定測試數據下解釋測試結果分類,NN(Neural Network)分類就難以解釋,至少沒有Decision Tree模型明晰。

5:易於使用統計數據驗證模型,可以解釋模型的可用性和可信賴度

6:健壯,數據假設比較少,該模型僅僅依賴於觀察到的數據,歸於數據生成模型假設比較少。

7:在大數據量狀況下也能很快給出結果,根據Decision Tree抽取出來的規則可以很快的運用於測試數據,運行快速。

 

缺點:

1:最優Decision Tree是NP難題,因此使用的Decision-Tree算法都是基於啓發式(Heuristic)算法,如Greedy Algorithm等,在每一個節點判斷都是根據局部最優解來進行操做。啓發式算法不能保證返回全局最優的Decision Tree。

2:容易產生過於複雜的樹,不能很好地得到數據的通用模型,這個其實是被稱爲是Overfitting,剪枝技術可以很好的避免這個問題。

3:Decision Tree的表示能力有限,只能表示有限的數據操做,如XOR、Parity、Multiplexer等操做就不易表示;致使Decision Tree變得特別大,解決方法可使用改變問題域的表示(Propositionalisation),或者使用更加複雜的表示方法,如Statistical Relational Learning、Inductive Logic Programming等。

4:對於包含分類變量(Categorical Variable)的數據,使用Information Gain分裂會形成較大的誤差

 

Extension:

Decision Tree使用And或者是Conjunction來在Decision Node進行判斷,逐步獲得結果;Decision Graph則是使用Or或者Disjunction來鏈接路徑(判斷條件)。在Decision Graph中,使用MML(Minimum Message length)來對Path進行處理,更細節的內容請自行查找。

關於Decision Tree的實現比較多,其中Weka中有一部分Decision Tree的經典算法實現,你們能夠將weka的源碼下載下來,仔細閱讀下。

 

Decision Tree:ID三、C4.5

 

ID3(Iterative Dichotomiser 3)算法是斷定樹算法(Decision Tree Learning)的典型表明算法,由Ross Quinlan在1975年提出。ID3是做爲C4.5的先驅,在Machine Learning和Natural Language Processing中使用普遍。該分類算法的核心是Entropy理論,屬於數學的範疇。Entropy Theory是信息論中的名詞,在上篇文章中http://isilic.iteye.com/blog/1841339有介紹,不過關於信息熵還有一些更深一些的東西。

信息熵

信息熵是指:一組數據所包含的信息量,使用機率來度量。數據包含的信息越有序,所包含的信息越低;數據包含的信息越雜,包含的信息越高。例如在極端狀況下,若是數據中的信息都是0,或者都是1,那麼熵值爲0,由於你從這些數據中得不到任何信息,或者說這組數據給出的信息是肯定的。若是數據時均勻分佈,那麼他的熵最大,由於你根據數據不能知曉那種狀況發生的可能性比較大。

計算熵的公式爲:

 

熵值和機率的關係以下,這個是二值狀況下的機率與熵值關係,其中n=2:

 

實際上,信息熵表示的是信息的不肯定性。當機率相同時,不肯定性越大,由於全部的信息機率相同,你不能肯定哪一個信息出現的可能性更大;當某類別發生的機率爲0或者1時,給出的結果是肯定的(出現或者不出現、發生或者不發生)。這樣的解釋會不會更清楚點。

 

Information Gain(IG),信息增益和信息熵描述的信息是一致的;描述的是對於數據集合S,將其按照其屬性A切分後,得到的信息增益值。注意IG描述的是信息的增益值,當不肯定性越大時,信息增益值應該是越小,反之亦然,是負相關的關係。信息增益的公式以下:

 

在ID3中,使用信息增益(IG)或者熵(Entropy)值來肯定使用哪一個屬性進行斷定屬性,能夠說是ID3算法的關鍵和精髓所在。ID3算法的僞碼以下:

 

ID3算法的原理仍是比較簡單的,其理論基礎是Entropy理論和Information Gain理論,只要深刻理解了這個內容,ID3算法就不是問題。其實Machine Learning的基礎是統計、機率、幾何知識的考量,數學基礎好的話,會在學習過程當中感受輕鬆些。

 

在Machine Learning in Action中有個章節是介紹ID3算法的,而且有完整的實現。我將代碼拿過來,感興趣的能夠結合理論學習一下。 

 

Python代碼  
  1. from math import log  
  2. import operator  
  3.   
  4. def createDataSet():  
  5.     dataSet = [[1, 1, 'yes'],  
  6.                [1, 1, 'yes'],  
  7.                [1, 0, 'no'],  
  8.                [0, 1, 'no'],  
  9.                [0, 1, 'no']]  
  10.     labels = ['no surfacing','flippers']  
  11.     #change to discrete values  
  12.     return dataSet, labels  
  13.   
  14. def calcShannonEnt(dataSet):  
  15.     numEntries = len(dataSet)  
  16.     labelCounts = {}  
  17.     for featVec in dataSet: #the the number of unique elements and their occurance  
  18.         currentLabel = featVec[-1]  
  19.         if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0  
  20.         labelCounts[currentLabel] += 1  
  21.     shannonEnt = 0.0  
  22.     for key in labelCounts:  
  23.         prob = float(labelCounts[key])/numEntries  
  24.         shannonEnt -= prob * log(prob,2) #log base 2  
  25.     return shannonEnt  
  26.   
  27. def splitDataSet(dataSet, axis, value):  
  28.     retDataSet = []  
  29.     for featVec in dataSet:  
  30.         if featVec[axis] == value:  
  31.             reducedFeatVec = featVec[:axis]     #chop out axis used for splitting  
  32.             reducedFeatVec.extend(featVec[axis+1:])  
  33.             retDataSet.append(reducedFeatVec)  
  34.     return retDataSet  
  35.   
  36. def chooseBestFeatureToSplit(dataSet):  
  37.     numFeatures = len(dataSet[0]) - 1      #the last column is used for the labels  
  38.     baseEntropy = calcShannonEnt(dataSet)  
  39.     bestInfoGain = 0.0; bestFeature = -1  
  40.     for i in range(numFeatures):        #iterate over all the features  
  41.         featList = [example[i] for example in dataSet]#create a list of all the examples of this feature  
  42.         uniqueVals = set(featList)       #get a set of unique values  
  43.         newEntropy = 0.0  
  44.         for value in uniqueVals:  
  45.             subDataSet = splitDataSet(dataSet, i, value)  
  46.             prob = len(subDataSet)/float(len(dataSet))  
  47.             newEntropy += prob * calcShannonEnt(subDataSet)  
  48.         infoGain = baseEntropy - newEntropy     #calculate the info gain; ie reduction in entropy  
  49.         if (infoGain > bestInfoGain):       #compare this to the best gain so far  
  50.             bestInfoGain = infoGain         #if better than current best, set to best  
  51.             bestFeature = i  
  52.     return bestFeature                      #returns an integer  
  53.   
  54. def majorityCnt(classList):  
  55.     classCount={}  
  56.     for vote in classList:  
  57.         if vote not in classCount.keys(): classCount[vote] = 0  
  58.         classCount[vote] += 1  
  59.     sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)  
  60.     return sortedClassCount[0][0]  
  61.   
  62. def createTree(dataSet,labels):  
  63.     classList = [example[-1] for example in dataSet]  
  64.     if classList.count(classList[0]) == len(classList):  
  65.         return classList[0]#stop splitting when all of the classes are equal  
  66.     if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet  
  67.         return majorityCnt(classList)  
  68.     bestFeat = chooseBestFeatureToSplit(dataSet)  
  69.     bestFeatLabel = labels[bestFeat]  
  70.     myTree = {bestFeatLabel:{}}  
  71.     del(labels[bestFeat])  
  72.     featValues = [example[bestFeat] for example in dataSet]  
  73.     uniqueVals = set(featValues)  
  74.     for value in uniqueVals:  
  75.         subLabels = labels[:]       #copy all of labels, so trees don't mess up existing labels  
  76.         myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)  
  77.     return myTree  
  78.   
  79. def classify(inputTree,featLabels,testVec):  
  80.     firstStr = inputTree.keys()[0]  
  81.     secondDict = inputTree[firstStr]  
  82.     featIndex = featLabels.index(firstStr)  
  83.     key = testVec[featIndex]  
  84.     valueOfFeat = secondDict[key]  
  85.     if isinstance(valueOfFeat, dict):  
  86.         classLabel = classify(valueOfFeat, featLabels, testVec)  
  87.     else: classLabel = valueOfFeat  
  88.     return classLabel  
  89.   
  90. def storeTree(inputTree,filename):  
  91.     import pickle  
  92.     fw = open(filename,'w')  
  93.     pickle.dump(inputTree,fw)  
  94.     fw.close()  
  95.   
  96. def grabTree(filename):  
  97.     import pickle  
  98.     fr = open(filename)  
  99.     return pickle.load(fr)  

 代碼還算清晰,chooseBestFeatureToSplit和calcShannonEnt這兩個方法是ID3算法的核心,請仔細閱讀代碼,肯定本身真正理解了熵理論和信息增益理論。

  

ID3算法存在的缺點: 

1:ID3算法在選擇根節點和內部節點中的分支屬性時,採用信息增益做爲評價標準。信息增益的缺點是傾向於選擇取值較可能是屬性在有些狀況下這類屬性可能不會提供太多有價值的信息。 

2:ID3算法只能對描述屬性爲離散型屬性的數據集構造決策樹 

 

ID3算法的侷限是它的屬性只能取離散值,爲了使決策樹能應用於連續屬性值狀況,Quinlan給出了ID3的一個擴展算法:即C4.5算法。C4.5算法是ID3的改進,其中離散屬性值的選擇依據同ID3;它對於實值變量的處理採用多重分支。C4.5算法能實現基於規則的剪枝。由於算法生成的每一個葉子都和一條規則相關聯,這個規則能夠從樹的根節點直到葉子節點的路徑上以邏輯合取式的形式讀出。

 

C4.5算法之因此是最經常使用的決策樹算法,是由於它繼承了ID3算法的全部優勢並對ID3算的進行了改進和補充。C4.5算法採用信息增益率做爲選擇分支屬性的標準,並克服了ID3算法中信息增益選擇屬性時偏向選擇取值多的屬性的不足,並可以完成對連續屬性離散化是處理;還可以對不完整數據進行處理。C4.5算法屬於基於信息論Information Theory的方法,以信息論爲基礎,以信息熵和信息增益度爲衡量標準,從而實現對數據的概括和分類。 

C4.5算法主要作出瞭如下方面的改進 

1:能夠處理連續數值型屬性 

對於離散值,C4.5和ID3的處理方法相同,對於某個屬性的值連續時,假設這這個節點上的數據集合樣本爲total,C4.5算法進行以下處理: 

  • 將樣本數據該屬性A上的具體數值按照升序排列,獲得屬性序列值:{A1,A2,A3,...,Atotal}
  • 在上一步生成的序列值中生成total-1個分割點。第i個分割點的取值爲Ai和Ai+1的均值,每一個分割點都將屬性序列劃分爲兩個子集。
  • 計算每一個分割點的信息增益(Information Gain),獲得total-1個信息增益。
  • 對分裂點的信息增益進行修正:減去log2(N-1)/|D|,其中N爲可能的分裂點個數,D爲數據集合大小。
  • 選擇修正後的信息增益值最大的分類點做爲該屬性的最佳分類點
  • 計算最佳分裂點的信息增益率(Gain Ratio)做爲該屬性的Gain Ratio
  • 選擇Gain Ratio最大的屬性做爲分類屬性。

 其中第四、5步驟Quinlan在93年的的算法中沒有體現,在96年發表文章對該算法進行改進,改進的論文能夠參考這裏:http://www.cs.cmu.edu/afs/cs/project/jair/pub/volume4/quinlan96a.pdf。 

 

2:用信息增益率(Information Gain Ratio)來選擇屬性 

克服了用信息增益來選擇屬性時偏向選擇值多的屬性的不足。信息增益率定義爲: 

 

其中Gain(S,A)和ID3算法中的信息增益計算相同,而SplitInfo(S,A)表明了按照屬性A分裂樣本集合S的廣度和均勻性。

 

其中Si表示根據屬性A分割S而成的樣本子集。 

 

3:後剪枝策略 

Decision Tree很容易產生Overfitting,剪枝可以避免樹高度無限制增加,避免過分擬合數據。剪枝算法比較複雜,我本身尚未學習清楚,但願你們能提供學習這個剪枝策略方法的建議。 

 

4:缺失值處理 

對於某些採樣數據,可能會缺乏屬性值。在這種狀況下,處理缺乏屬性值的一般作法是賦予該屬性的常見值,或者屬性均值。另一種比較好的方法是爲該屬性的每一個可能值賦予一個機率,即將該屬性以機率形式賦值。例如給定Boolean屬性B,已知採樣數據有12個B=0和88個B=1實例,那麼在賦值過程當中,B屬性的缺失值被賦值爲B(0)=0.十二、B(1)=0.88;因此屬性B的缺失值以12%機率被分到False的分支,以88%機率被分到True的分支。這種處理的目的是計算信息增益,使得這種屬性值缺失的樣本也能處理。

 

咱們看下C4.5算法的僞碼: 

僞碼代碼  
  1. Function C4.5(R:包含連續屬性的無類別屬性集合,C:類別屬性,S:訓練集)    
  2. Begin    
  3.    If S爲空,返回一個值爲Failure的單個節點;    
  4.    If S是由相同類別屬性值的記錄組成,    
  5.       返回一個帶有該值的單個節點;    
  6.    If R爲空,則返回一個單節點,其值爲在S的記錄中找出的頻率最高的類別屬性值;    
  7.    [注意未出現錯誤則意味着是不適合分類的記錄];    
  8.   For 全部的屬性R(Ri) Do    
  9.         If 屬性Ri爲連續屬性,則    
  10.         Begin    
  11.            sort(Ri屬性值)  
  12.            將Ri的最小值賦給A1:    
  13.              將Ri的最大值賦給Am;    
  14.            For j From 1 To m-1 Do Aj=(A1+Aj+1)/2;    
  15.            將Ri點的基於Aj(1<=j<=m-1劃分的最大信息增益屬性(Ri,S)賦給A;    
  16.         End;    
  17.   將R中屬性之間具備最大信息增益的屬性(D,S)賦給D;    
  18.   將屬性D的值賦給{dj/j=1,2...m};    
  19.   將分別由對應於D的值爲dj的記錄組成的S的子集賦給{sj/j=1,2...m};    
  20.   返回一棵樹,其根標記爲D;樹枝標記爲d1,d2...dm;    
  21.   再分別構造如下樹:    
  22.   C4.5(R-{D},C,S1),C4.5(R-{D},C,S2)...C4.5(R-{D},C,Sm);    
  23. End C4.5  

 該算法流程是我從網上移過來的,對於其中和本文描述不一致的地方作了修改。原文參考這裏:http://blog.sina.com.cn/s/blog_73621a3201017g7k.html

C4.5的主要點在於對於ID3的改進,能夠說上面提到的四點對於Decision Tree算法來講是很是關鍵的,理解了這幾個改進點就算是掌握了C4.5算法的根本。

 

C4.5的缺點:

1:算法低效,在構造樹的過程當中,須要對數據集進行屢次的順序掃描和排序,於是致使算法的低效

2:內存受限,適合於可以駐留於內存的數據集,當訓練集大得沒法在內存容納時程序沒法運行。

 

在weka開源軟件中有個weka.classifiers.trees.J48實現了C4.5算法,能夠結合該代碼學習理論知識。

 

最後提示下C5.0算法,C5.0算法是在C4.5算法基礎上的改進,wiki上表示該算法應該歸屬於商業應用,因此沒有C4.5討論普遍。相比較於C4.5,C5.0算法的改進點在於:

1:速度,C5.0有好幾個數量級別上的速度提高

2:內存使用,比C4.5使用更加有效

3:生成Decision Tree更小(Occam's Razor),能避免過分擬合

4:支持Boosting

5:支持權重,對於不一樣的樣本賦予不一樣的權重值

6:Winnowing:支持自動去除沒有幫助的屬性

這個是做者的聲明。尤爲是前兩點,恰好是克服了C4.5算法的劣勢,是C4.5算法的巨大提高,算法源碼在http://rulequest.com/download.html這裏有下載,你們能夠學習下做者聲稱的優點都是怎麼實現的。在這裏http://www.rulequest.com/see5-comparison.html有C5.0和C4.5的比較,你們也能夠看下,從文章來看,C5.0確實是在不少方面都超過了C4.5。

 

本文關於Decision Tree的學習到此,本文介紹了最爲簡單和基礎的ID3算法;隨後學習了C4.5相比於ID3的優點及實現思路;最後比較了C5.0的改進;對於Decision Tree算法有了基本的認識,爲後面學習Decision Tree算法提供了良好的基礎。

 

Decision Tree:CART、剪枝

 

決策樹的重要性和入門能夠參考前面兩篇文章,尤爲是入門的ID3算法:

http://isilic.iteye.com/blog/1841339http://isilic.iteye.com/blog/1844097

Classification And Regression Tree(CART)也是決策樹的一種,而且是很是重要的決策樹。除去上文提到的C4.5外,CART算法也在Top Ten Machine Learning Algorithm中,可見決策樹的重要性和CART算法的重要性。

 

CART的特性主要有下面三個,其實這些特性都不徹底算是CART的特性,只是在CART算法中使用,而且做爲算法的重要基礎:

1:二分(Binary Split):在每次判斷過程當中,都是對觀察變量進行二分。

2:單變量分割(Split Based on One Variable):每次最優劃分都是針對單個變量。

3:剪枝策略:CART算法的關鍵點,也是整個Tree-Based算法的關鍵步驟。

 

CART能處理Classification Tree和Regression Tree,在建樹過程當中有不同的地方,咱們分別來看下。

咱們先看Classification Tree的建樹過程:

ID3,C4.5算法是利用熵理論和信息增益(率)來決定屬性分割策略;CART則是利用Gini Index(GINI 指數)來定義衡量劃分的好壞。和熵相似,數據內包含的類別越雜亂,GINI指數就越大,有沒有感受跟熵的概念相似。下面咱們來學習下Gini Index的內容:

 

其中Pj是類j在T中的相對頻率,當類j在T中是傾斜時,gini(T)纔會最小。

比較熵理論和gini指數,讓T中各種別出現的機率一致時,熵最大,Gini指數也是最大,可是二者的逼近速度是不同的,從下圖中能夠看出來:

 

其中MisClassification Rate也是一種衡量,感興趣的同窗能夠自行學習下。

 

衡量出某個屬性的Gini指數後,能夠獲得Gini Split數據以下:

 

這個有沒有和信息增益類似,這個能夠稱爲是Gini信息增益,在CART中,選擇其中最小的Gini信息增益做爲結點劃分決策樹。

對於CART,i=2,能夠獲得在Binary Split狀況下的Gini信息增益:

 

在weka中有信息增益weka.attributeSelection.InfoGainAttributeEval和信息增益率 weka.attributeSelection.GainRatioAttributeEval 的實現,能夠看下實現原理。

 

Regression Tree的建樹過程。

對於迴歸樹,沒有分類數據,只有根據觀察數據得出的值,注意觀察值取值是連續,在這種狀況下Classification Tree的最優劃分規則就無能爲力。

在這種狀況下,迴歸樹可使用 最小剩餘方差(Squared Residuals Minimization)來決定Regression Tree的最優劃分,該劃分準則是指望劃分以後的子樹偏差方差最小:

 

決策樹中止生長的條件,這個能夠看作是預剪枝過程:

樹不能無限增加,咱們能夠設定條件,當樹達到某個中止條件時,中止樹增加,經常使用的中止條件(Stopping Criteria)有以下幾個:

  • 1:子樹上的樣本數據都歸屬於同一個類別
  • 2:達到最大數深度(Maximum Tree Depth)
  • 3:子樹節點的樣本數量要少於某個門限值,或者小於必定的比例
  • 4:子樹節點再按照最優劃分標準切分,其子樹的樣本數量小於某個門限值,或者小於必定的比例值
  • 5:最優劃分(Split)標增益小於某個門限值,如偏差值等

這些方法均可以讓樹提早中止增加,防止樹無限制生成,避免必定程度上的過擬合。

 

剪枝理論,決策樹的剪枝在上一節中沒有仔細講,趁這個機會學習了剪枝的基礎理論,這裏會詳細學習。

決策樹爲何(WHY)要剪枝?緣由是避免決策樹過擬合(Overfitting)樣本。前面的算法生成的決策樹很是詳細而且龐大,每一個屬性都被詳細地加以考慮,決策樹的樹葉節點所覆蓋的訓練樣本都是「純」的。所以用這個決策樹來對訓練樣本進行分類的話,你會發現對於訓練樣本而言,這個樹表現無缺,偏差率極低且可以正確得對訓練樣本集中的樣本進行分類。訓練樣本中的錯誤數據也會被決策樹學習,成爲決策樹的部分,可是對於測試數據的表現就沒有想象的那麼好,或者極差,這就是所謂的過擬合(Overfitting)問題。Quinlan教授試驗,在數據集中,過擬合的決策樹的錯誤率比通過簡化的決策樹的錯誤率要高。

 

如今問題就在於,如何(HOW)在原生的過擬合決策樹的基礎上,生成簡化版的決策樹?能夠經過剪枝的方法來簡化過擬合的決策樹。剪枝能夠分爲兩種:預剪枝(Pre-Pruning)和後剪枝(Post-Pruning),下面咱們來詳細學習下這兩種方法:

PrePrune:預剪枝,及早的中止樹增加,方法能夠參考見上面樹中止增加的方法。

PostPrune:後剪枝,在已生成過擬合決策樹上進行剪枝,能夠獲得簡化版的剪枝決策樹。

其實剪枝的準則是如何肯定決策樹的規模,能夠參考的剪枝思路有如下幾個:

1:使用訓練集合(Training Set)和驗證集合(Validation Set),來評估剪枝方法在修剪結點上的效用

2:使用全部的訓練集合進行訓練,可是用統計測試來估計修剪特定結點是否會改善訓練集合外的數據的評估性能,如使用Chi-Square(Quinlan,1986)測試來進一步擴展結點是否能改善整個分類數據的性能,仍是僅僅改善了當前訓練集合數據上的性能。

3:使用明確的標準來衡量訓練樣例和決策樹的複雜度,當編碼長度最小時,中止樹增加,如MDL(Minimum Description Length)準則。

 

咱們先看下使用思路一來解決問題的集中後剪枝方法:

Reduced-Error Pruning(REP,錯誤率下降剪枝)

該剪枝方法考慮將書上的每一個節點做爲修剪的候選對象,決定是否修剪這個結點有以下步驟組成:

1:刪除以此結點爲根的子樹

2:使其成爲葉子結點

3:賦予該結點關聯的訓練數據的最多見分類

4:當修剪後的樹對於驗證集合的性能不會比原來的樹差時,才真正刪除該結點

由於訓練集合的過擬合,使得驗證集合數據可以對其進行修正,反覆進行上面的操做,從底向上的處理結點,刪除那些可以最大限度的提升驗證集合的精度的結點,直到進一步修剪有害爲止(有害是指修剪會減低驗證集合的精度)

REP是最簡單的後剪枝方法之一,不過在數據量比較少的狀況下,REP方法趨於過擬合而較少使用。這是由於訓練數據集合中的特性在剪枝過程當中被忽略,因此在驗證數據集合比訓練數據集合小的多時,要注意這個問題。

儘管REP有這個缺點,不過REP仍然做爲一種基準來評價其它剪枝算法的性能。它對於兩階段決策樹學習方法的優勢和缺點提供了了一個很好的學習思路。因爲驗證集合沒有參與決策樹的建立,因此用REP剪枝後的決策樹對於測試樣例的誤差要好不少,可以解決必定程度的過擬合問題。

 

Pessimistic Error Pruning(PEP,悲觀剪枝)

先計算規則在它應用的訓練樣例上的精度,而後假定此估計精度爲二項式分佈,並計算它的標準差。對於給定的置信區間,採用下界估計做爲規則性能的度量。這樣作的結果,是對於大的數據集合,該剪枝策略可以很是接近觀察精度,隨着數據集合的減少,離觀察精度愈來愈遠。該剪枝方法儘管不是統計有效的,可是在實踐中有效。

PEP爲了提升對測試集合的預測可靠性,PEP對偏差估計增長了連續性校訂(Continuity Correction)。PEP方法認爲,若是: 

成立,則Tt應該被剪枝,上式中: 

 

 

其中,e(t)爲結點t出的偏差;i爲覆蓋Tt的葉子結點;Nt爲子樹Tt的葉子樹;n(t)爲在結點t處的訓練集合數量。PEP採用自頂向下的方式,若是某個非葉子結點符合上面的不等式,就裁剪掉該葉子結點。該算法被認爲是當前決策樹後剪枝算法中經度比較高的算法之一,可是餓存在有缺陷。首先,PEP算法是惟一使用Top-Down剪枝策略,這種策略會致使與先剪枝出現一樣的問題,將該結點的某子節點不須要被剪枝時被剪掉;另外PEP方法會有剪枝失敗的狀況出現。

雖然PEP方法存在一些侷限性,可是在實際應用中表現出了較高的精度,。兩外PEP方法不須要分離訓練集合和驗證機和,對於數據量比較少的狀況比較有利。再者其剪枝策略比其它方法相比效率更高,速度更快。由於在剪枝過程當中,樹中的每顆子樹最多須要訪問一次,在最壞的狀況下,它的計算時間複雜度也只和非剪枝樹的非葉子節點數目成線性關係。

可能有同窗會對上面的那個不等式有疑問,能夠參考這篇文章http://blog.sina.com.cn/s/blog_68ffc7a40100urn3.html 中關於PEP剪枝部份內容。PEP方法其實是將結點偏差數目看作二項式分佈,根據指望和方差獲得的結果。

 

Cost-Complexity Pruning(CCP、代價複雜度)

CCP方法包含兩個步驟:

1:從原始決策樹T0開始生成一個子樹序列{T0、T一、T二、...、Tn},其中Ti+1是從Ti總產生,Tn爲根節點

2:從子樹序列中,根據樹的真實偏差估計選擇最佳決策樹。

在步驟一中,生成子樹序列{T0、T一、T二、...、Tn}的基本思想是從T0開始,裁剪Ti中關於訓練數據集合偏差增長最小的分支來獲得Ti+1。實際上當一棵樹T在結點t出剪枝時,它的偏差增長直觀上認爲是:

 

其中R(t)爲在結點t的子樹被裁剪後結點t的偏差,R(Tt)爲在結點t的子樹沒被裁剪時子樹T的偏差。不過剪枝後T的葉子樹減小了|L(Ti)|-1,其中|L(Ti)|爲子樹Ti的葉子樹,也就是說T的複雜性下降。所以考慮到樹的複雜性因素,樹分支被裁剪後偏差增長率能夠由下式決定:

 Ti+1就是選擇Ti中具備最小\alpha值所對應的剪枝樹

如何從第一步驟產生的子樹序列{T0、T一、T二、...、Tn}中選擇出最佳決策樹是CCP方法的第二步驟的關鍵。一般能夠採用V-交叉驗證(V-fold Cross-Validation)和基於獨立剪枝數據集兩種方法,這兩種方法能夠參考(Classification And Regression Trees,Breiman et.al)。當使用基於獨立數據集剪枝時,和REP方法相比,CCP選擇出來的最有決策樹,不是從原始決策樹T的全部可能子樹中獲得,因此有可能會找到到最有決策樹。

 

其它如Minimum Error Pruning(MEP),Critical Value Pruning(CVP),Optimal Pruning(OPP),Cost-Sensitive Decision Tree Pruning(CSDTP)等方法,這些剪枝方法各有利弊,關注不一樣的優化點,感興趣的同窗能夠學習下。

 

剪枝過程特別重要,因此在最優決策樹生成過程當中佔有重要地位。有研究代表,剪枝過程的重要性要比樹生成過程更爲重要,對於不一樣的劃分標準生成的最大樹(Maximum Tree),在剪枝以後都可以保留最重要的屬性劃分,差異不大。反而是剪枝方法對於最優樹的生成更爲關鍵。重點理解這些剪枝方法的理論,對於最終最優樹的生成是有好處的,其中上篇文章http://isilic.iteye.com/blog/1844097中C4.5使用了PEP剪枝方法,本文的CART使用了CCP的剪枝方法,實際上,不該該對於算法使用的剪枝方法過於追根究底,而是應該對於剪枝過程理解透徹,對於在何種場景下對於不一樣的數據類型使用何種的剪枝方法可以得到最優樹的選擇,纔是真正理解了剪枝的理論和重要性。

 

下面再回到CART算法,看下算法的優勢:

1:沒有分佈假設、沒有數據同質性(Homogeneity)要求

2:觀測值屬性能夠是分類、離散、連續的混合。

4:對異常值(Outlier)值不敏感,異常值通常會被處理掉

5:在面對缺失值、變量多等問題時,CART顯得給長穩健(ROBUST)

 

缺點:

1:非基於機率模型,很難對決策樹的結果的準確程度作度量

 

CART算法的內容就到這裏,再擴充下Decision Tree算法的內容。上面的這些決策樹算法都是單變量(Univariate)算法,實際上還有多變量(MultiVariate)算法,只是使用比較少。在Machine Learning In Action第九章中有關於Tree-Based Regression,是講解CART中Regression樹的內容。尤爲是在文章中間提到了多變量回歸樹算法,每次的斷定點有兩個變量組成,對於本文的內容是個很是好的擴充,能夠學習下。另外要提一下的是該章節中講解的CART生成比較簡單,尤爲是生成最大樹的方法;不過樹生成和數剪枝(包括預剪枝和後剪枝)都有體現,算是分不錯的代碼文檔;感興趣的能夠直接在這份代碼上修改。

 

後面附加了份關於決策樹的概論內容綜述,地址參見:http://www.ise.bgu.ac.il/faculty/liorr/hbchap9.pdf 。內容比較全,包括劃分標準、剪枝方法,不過不夠深刻,只有公式和簡單的介紹,若是有基礎的話話,卻是份不錯的文檔。若是不能觀看的話,文後有附件。

另外在百度文庫上有個PPT不錯:http://wenku.baidu.com/view/415c3cc19ec3d5bbfd0a7464.html,供參考。

 

其實本文的重點是剪枝的內容,除去這點,CART算法使用的GINI指數內容也是本文的重點。

本文內容結束。 

 

以上內容轉自:http://isilic.iteye.com/blog/1841339

http://isilic.iteye.com/blog/1844097

http://isilic.iteye.com/blog/1846726

相關文章
相關標籤/搜索