決策樹有着非常廣泛的應用,可以用於分類和回歸問題。以下針對分類問題對決策樹進行分析。
分類情況下,可以處理離散(if-then)的特征空間,也可以是連續(閾值化的if-than)的特征空間。
決策樹由結點和邊構成,其中結點分內結點(屬性,特征)和外結點(類別)。邊上代表着判別的規則,即if-then規則——Splitting datasets one feature at a time.
思想,決策樹的每個分枝根據邊代表的屬性利用if-then規則將特征分類,直至獲得分類的結果。
決策樹的訓練屬於監督學習,訓練生成的決策樹作為分類器用於新樣本的分類決策。因為決策樹的生成可能會產生過擬合,需要提前停止樹的生成或剪枝來解決。
決策樹的三個主要問題,特征選擇,生成,剪枝。其中特征的選擇的概念,即熵、信息增益/比的概念很重要。
決策樹的主要流行方法有,CD3,C4.5,CART。
決策樹的優點:
一、 決策樹易於理解和解釋.人們在通過解釋后都有能力去理解決策樹所表達的意義。
二、 對於決策樹,數據的准備往往是簡單或者是不必要的.其他的技術往往要求先把數據一般化,比如去掉多余的或者空白的屬性。
三、 能夠同時處理數據型和常規型屬性。其他的技術往往要求數據屬性的單一。
四、 決策樹是一個白盒模型。如果給定一個觀察的模型,那么根據所產生的決策樹很容易推出相應的邏輯表達式。
五、 易於通過靜態測試來對模型進行評測。表示有可能測量該模型的可信度。
六、 在相對短的時間內能夠對大型數據源做出可行且效果良好的結果。
七、 可以對有許多屬性的數據集構造決策樹。
八、 決策樹可很好地擴展到大型數據庫中,同時它的大小獨立於數據庫的大小。
決策樹的缺點:
一、 對於那些各類別樣本數量不一致的數據,在決策樹當中,信息增益的結果偏向於那些具有更多數值的特征。
二、 決策樹處理缺失數據時的困難。
三、 過度擬合問題的出現。
四、 忽略數據集中屬性之間的相關性。
先舉個簡單例子,來分析基本要素和概念
下圖是weka軟件安裝目錄下自帶的測試數據例子。

這個數據文件內容表示的意思是:在不同的天氣情況下,是否去玩。
一共有14個實例(天數),五種屬性(天氣外觀,溫度,濕度,有無風,是否玩),前四種是特征,最后一種是分類結果。這個例子的數值域都是離散的。
就以這個例子講決策樹的基本概念。
以下是weka中用決策樹J48 (C4.5)算法生成的例子。

根據這個圖我們來分析下決策樹的基本要素。
決策樹結構,結點和邊構成的決策樹,其中結點分內結點(特征)和外結點(類別)
邊上代表着判別的規則,即if-then規則。I.E. Splitting datasets one feature at a time
發現沒有少用了一個特征"溫度",因為這個特征最不重要,而且加上它有可能並不能提高整體性能,即可能產生過擬合。
為了避免過擬合,辦法有提前終止樹的生成,和剪枝。
綜上,決策樹的三個主要問題,特征選擇,生成,剪枝。具體細節請看《統計學習理論》李航。以下只敘述大致框架和要點
if-then規則
一共有14個實例,每個實例可以建立一個if-then規則來確定分類,如第1個實例:if(天氣晴,溫度高,濕度大,無風),then(不玩)。那么根據訓練數據就可建立14種規則,但是一共有4!種情況,對新的實例並不能很好的分類,因此並不能這樣簡單的建立。
那該如何建立呢,根據機器學習監督學習分類的基本目標,要建立一套規則能很好的擬合訓練實例情況,又能夠有很好的泛化能力,即預測未知實例情況。所以在if-then規則中,要選取最好的特征來進行分類。
特征選擇
那什么是較好的特征呢?想想看,如果取極端的情況,要求這個例子中四個特征中只選擇一個特征來進行分類,你會選擇哪個作為if的判別條件呢?也就是選定一個特征后,其他特征先不看,根據這個特征從訓練實例中來建立if-then規則進行分類,比如選第十個特征"風",8次無風情況下其中2次不去,6次有風情況下其中3次不去。那么根據概率大的情況作為判定結果。規則是:if(有風),then(不去或者去,因為概率一樣);if(無風),then(去)。根據這樣的規則就能建立一個樹結構模型。還能算出訓練的錯誤率為(2+3)/14。然后看看分別單獨選不同情況下的錯誤率哪個最小。顯然為了使得訓練誤差要小,就選擇那樣的特征——錯誤率哪個最小代表的特征。這種很好理解的規則,就是使分類誤差率最小。
根據這樣的方法選好的以一個if-then規則中使用的特征,然后根據情況划分成幾塊情況,每塊又可以重復上述過程,程序中表現為迭代。每次選擇特征使用的方法就是啟發式算法,得到次優解。因為建立一套整體規則是NP問題,並且生成這一套整體規則可以用樹來表示,稱之為決策樹。
那還有哪些啟發式算法可以作為選特征的依據嗎?看下圖

是的,還有熵、基尼指數可以作為選取特征的衡量標准來使用。下面就只說關於熵的。
信息增益

一句話:熵也大,隨機變量的不確定性也越大。

因此選擇信息增益大的特征,來作為if-then規則的判別條件,這就是決策樹ID3的核心思想。
而改進的C4.5算法中,使用的是如下信息增益比來選取特征。

以下例子和程序來自《機器學習實戰》第三章,以ID3算法為例,程序不全,附件有全程序是課本的代碼。
程序:計算熵
1 def calcShannonEnt(dataSet): 2 numEntries = len(dataSet) 3 labelCounts = {} 4 for featVec in dataSet: #the the number of unique elements and their occurance 5 currentLabel = featVec[-1] 6 if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0 7 labelCounts[currentLabel] += 1 8 shannonEnt = 0.0 9 for key in labelCounts: 10 prob = float(labelCounts[key])/numEntries 11 shannonEnt -= prob * log(prob,2) #log base 2 12 return shannonEnt
程序:根據信息增益比來選取特征
1 def chooseBestFeatureToSplit(dataSet): 2 numFeatures = len(dataSet[0]) - 1 #the last column is used for the labels 3 baseEntropy = calcShannonEnt(dataSet) 4 bestInfoGain = 0.0; bestFeature = -1 5 for i in range(numFeatures): #iterate over all the features 6 featList = [example[i] for example in dataSet]#create a list of all the examples of this feature 7 uniqueVals = set(featList) #get a set of unique values 8 newEntropy = 0.0 9 for value in uniqueVals: 10 subDataSet = splitDataSet(dataSet, i, value) 11 prob = len(subDataSet)/float(len(dataSet)) 12 newEntropy += prob * calcShannonEnt(subDataSet) 13 infoGain = baseEntropy - newEntropy #calculate the info gain; ie reduction in entropy 14 if (infoGain > bestInfoGain): #compare this to the best gain so far 15 bestInfoGain = infoGain #if better than current best, set to best 16 bestFeature = i 17 return bestFeature #returns an integer
樹的生成
內結點(特征)中選好特征來做為if-then規則的判別條件,根據不同情況在每條邊上划分結點,檢測結點是否滿足成為外結點(類別)的情況,滿足就把類別多的結果作為外結點(類別)表示的類。不滿足就就是內結點(特征),就重復上一句話的做法(遞推)。


程序:生成樹
1 def createTree(dataSet,labels): 2 classList = [example[-1] for example in dataSet] 3 if classList.count(classList[0]) == len(classList): 4 return classList[0]#stop splitting when all of the classes are equal 5 if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet 6 return majorityCnt(classList) 7 bestFeat = chooseBestFeatureToSplit(dataSet) 8 bestFeatLabel = labels[bestFeat] 9 myTree = {bestFeatLabel:{}} 10 del(labels[bestFeat]) 11 featValues = [example[bestFeat] for example in dataSet] 12 uniqueVals = set(featValues) 13 for value in uniqueVals: 14 subLabels = labels[:] #copy all of labels, so trees don't mess up existing labels 15 myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels) 16 return myTree
樹的剪枝
像CD3算法這樣遞歸的產生決策樹,因為規則用的過多,過細,樹會建的很大,可能會較好的擬合訓練數據,但容易產生過擬合,不能很好的預測未知數據的分類結果。
為了避免過擬合,辦法有提前終止樹的生成,和剪枝。
避免過擬合的方法:



測試數據
構建好的決策樹,可以保存好,用於測試集進行分類。
程序:使用構建好的決策樹來對測試集進行分類
1 def classify(inputTree,featLabels,testVec): 2 firstStr = inputTree.keys()[0] 3 secondDict = inputTree[firstStr] 4 featIndex = featLabels.index(firstStr) 5 key = testVec[featIndex] 6 valueOfFeat = secondDict[key] 7 if isinstance(valueOfFeat, dict): 8 classLabel = classify(valueOfFeat, featLabels, testVec) 9 else: classLabel = valueOfFeat 10 return classLabel
這是樹的存儲結構
{'tearRate': {'reduced': 'no lenses', 'normal': {'astigmatic': {'yes': {'prescript': {'hyper': {'age': {'pre': 'no lenses', 'presbyopic': 'no lenses', 'young': 'hard'}}, 'myope': 'hard'}}, 'no': {'age': {'pre': 'soft', 'presbyopic': {'prescript': {'hyper': 'soft', 'myope': 'no lenses'}}, 'young': 'soft'}}}}}}
決策樹的結構

新的測試數據就可以用以上規則來划分類型了。
附件:代碼 http://files.cnblogs.com/Jay-Zen/decision_trees.rar
參考:
《統計學習理論》,李航
《機器學習實戰》
pedro domingos's machine learning course at coursera
各種分類算法比較from http://bbs.pinggu.org/thread-2604496-1-1.html
