1. 介紹
決策樹是一種依托決策而建立起來的一種樹。在機器學習中,決策樹是一種預測模型,代表的是一種對象屬性與對象值之間的一種映射關系,每一個節點代表某個對象/分類,樹中的每一個分叉路徑代表某個可能的屬性值,而每一個葉子節點則對應從根節點到該葉子節點所經歷的路徑所表示的對象的值
通過訓練數據構建決策樹,可以高效的對未知的數據進行分類。決策數有兩大優點:
1)決策樹模型可以讀性好,具有描述性,有助於人工分析;
2)效率高,決策樹只需要一次構建,反復使用,每一次預測的最大計算次數不超過決策樹的深度。
決策樹是一顆樹形的數據結構,可以是多叉樹也可以是二叉樹,決策樹實際上是一種基於貪心策略構造的,每次選擇的都是最優的屬性進行分裂。
決策樹也是一種監督學習算法,它的樣本是(x,y)形式的輸入輸出樣例。
輸入:一組對象屬性
輸出:對象值(分類算法中得到某個類別)
決策樹中間計算過程:
統計學習方法中根據下表貸款數據表生成的決策樹如下,當給定一個人的特征屬性之后就能判斷能不能給他貸款。
由上面的示例可以看出決策樹模型是一個 if(){}else if(){} else(){}模型,這里它具有一個十分重要的性質:互斥並且完備(每一個實例都被一條路徑或者一條規則所覆蓋,而且只被一條路徑或一條規則所覆蓋)
一般可以將決策樹分為兩種類型,一種是 分類決策樹,也就是本篇所介紹的決策樹類型。另一種決策樹是 回歸決策樹(CART回歸樹),下一篇中再介紹。它們的主要區別是得到的結果是否是連續值還是一個類別(分類問題、回歸問題)。

2. 分類決策樹
看到上面的第一張決策樹的圖后,心中會產生幾個疑問:
1) 為什么將“有自己的房子”作為根節點?
2) 為什么有自己的房子分類結果就是“是”?
3) 如何選定下一個節點?…..
先介紹一下決策樹中必須明白的幾個概念:
2.1 熵與條件熵、經驗熵與檢驗條件熵
熵H(X):表示隨機變量不確定性的度量,如果一個變量的隨機性越大(不確定性),則它的熵越大。
計算公式:
條件熵H(Y|X):表示在已知隨機變量X的條件下隨機變量Y的不確定性。例如“有自己房子”條件下“貸款”的熵。
當熵和條件熵中的概率是由數據估計(特別是極大似然估計)得到時,所對應的熵與條件熵分別稱為經驗熵和經驗條件熵。
2.2 信息增益與信息增益比
信息增益:表示得知特征的信息使得類Y的信息的不確定性減少程度。
特征A對訓練數據集D的信息增益g(D,A):集合D的經驗熵H(D)與特征A給定條件下D的經驗條件熵H(D|A)之差。

假設數據D可以分為K個類(對應介紹中 貸款“是”,“否”),特征A(“有自己的房子”)有n個不同的取值(“有”,“無”)。
H(D): 對數據集D進行分類的不確定性。
H(D|A): 在特定A給定條件下對數據集D進行分類的不確定性。
它們的計算公式如下(統計學習方法中的解析)
既然已經有了信息增益為什么還要引入“信息增益比”呢?
在以信息增益划分到底采用那個特征時,存在偏向於選取值較多的特征的問題,所以這里引入的增益比相當於歸一化,使各個特曾的影響因子歸一化。
其中:

3. 決策樹算法——ID3 算法
當理解了上面信息熵和條件熵的概念后,ID3算法就很容易理解了。該算法解決的主要問題是:如何生成一個決策樹?
輸入:訓練數據集D,特征集A,閾值e
輸出: 決策樹 T
3.1 決策樹生成算法
ID3算法的核心是在決策樹各個子節點上應用信息增益准則選擇特征,遞歸的構建決策樹,具體方法是:從根節點開始,對節點計算所有可能的特征的信息增益,選擇信息增益最大的特征作為節點的特征,由該特征的不同取值建立子節點;再對子節點遞歸調用以上方法,構建決策樹。直到所有特征的信息增益均很小或沒有特征可以選擇為止。最后得到一個決策樹。
這其中會遇到一些問題:
1、若D中所有的實例屬於用一類C(k),則T為單節點數,並將類C(k)作為該節點的類標記
2、若A = null,則T為單節點樹,並將D中實例數最大的類C(k)作為該節點的類標記。
3、如果A(g)的信息增益比小於閾值e,則置T為單節點樹,並將D中實例數最大的類作為該節點的類標記。
4、隨着樹的向下生長,特征集也會逐漸減少(A-A(g)),父節點中出現的特征將會排除在特征選取中。
與ID3算法類似的算法 C4.5算法,與ID3唯一的不同是 它選取信息增益比作為特征選擇的標准,這樣可以減少過擬合。而ID3采用信息增益作為特征選擇的標准。
創建決策樹的偽代碼(createBranch函數):
1 檢測數據中的每個子項是否屬於同一個分類 2 if so return 類標簽 3 else 4 尋找划分數據集的最好特征 5 划分數據集 6 創建分支節點 7 for 每個划分的子集 8 調用 createBranch並增加返回結果到分支節點中 9 return 分支節點
3.2 決策樹的減枝
通過決策樹算法生成的決策樹往往對訓練數據的分類很精確,但對未知的測試數據的分類卻沒有那么准確,即出現過擬合現象。
在決策樹學習中將已生成的樹進行簡化的過程稱為剪枝。
決策樹的剪枝往往通過極小化決策樹整體的損失函數/代價函數來實現。 當剪枝后決策樹的損失值小於剪枝前損失函數值,那么該分支將會被剪掉。(從葉節點自下而上遍歷決策樹的每個節點,確定是否需要進行剪枝)
3.3 決策樹的損失函數:
《統計學習方法》中給出了損失函數的公式:
4. python 實現ID3決策樹生成
決策樹構建的組件圖如下:
數據准備(只作為算法測試)
def createDataSet(): dataSet = [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']] labels = ['no surfacing','flippers'] #change to discrete values return dataSet, labels
1. 計算信息熵的函數:
注: 輸入數據的最后一列為 數據標簽。
def calcShannonEnt(dataSet): numEntries = len(dataSet) labelCounts = {} for featVec in dataSet: #the the number of unique elements and their occurance currentLabel = featVec[-1] if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0 labelCounts[currentLabel] += 1 shannonEnt = 0.0 for key in labelCounts: prob = float(labelCounts[key])/numEntries shannonEnt -= prob * log(prob,2) #log base 2 return shannonEnt
2. 划分數據集
該函數的目的是篩選出 某一列值等於某個只的所有數據,放到一個新的矩陣中:
# dataSet: 原始測試數據 # axis : 測試數據的某一列 # value: 需要篩選的值 def splitDataSet(dataSet, axis, value): retDataSet = [] for featVec in dataSet: if featVec[axis] == value: reducedFeatVec = featVec[:axis] #chop out axis used for splitting reducedFeatVec.extend(featVec[axis+1:]) retDataSet.append(reducedFeatVec) return retDataSet
3. 計算最佳的數據划分方式
計算信息增益選取最佳的數據划分方式. (分別計算每個特征值的信息增益值,返回信息增益最大的特征值序號)
def chooseBestFeatureToSplit(dataSet): numFeatures = len(dataSet[0]) - 1 #特征值的數量 baseEntropy = calcShannonEnt(dataSet) bestInfoGain = 0.0; bestFeature = -1 #最佳特征值 for i in range(numFeatures): #遍歷每個特征值,計算信息增益 featList = [example[i] for example in dataSet] # 存放第i列,數據值的set uniqueVals = set(featList) #get a set of unique values newEntropy = 0.0 for value in uniqueVals: subDataSet = splitDataSet(dataSet, i, value) prob = len(subDataSet)/float(len(dataSet)) newEntropy += prob * calcShannonEnt(subDataSet) infoGain = baseEntropy - newEntropy #calculate the info gain; ie reduction in entropy if (infoGain > bestInfoGain): #compare this to the best gain so far bestInfoGain = infoGain #if better than current best, set to best bestFeature = i return bestFeature #returns an integer
注: 這里運用了信息增益,而並沒有使用信息增益比。
4.遞歸構建決策樹
有了前面的函數工具基礎,構建一顆決策樹也就不那么復雜了。
def createTree(dataSet,labels): classList = [example[-1] for example in dataSet] if classList.count(classList[0]) == len(classList): return classList[0]#stop splitting when all of the classes are equal #stop splitting when there are no more features in dataSet if len(dataSet[0]) == 1: return majorityCnt(classList) bestFeat = chooseBestFeatureToSplit(dataSet) bestFeatLabel = labels[bestFeat] myTree = {bestFeatLabel:{}} del(labels[bestFeat]) featValues = [example[bestFeat] for example in dataSet] uniqueVals = set(featValues) for value in uniqueVals: subLabels = labels[:] #copy all of labels, so trees don't mess up existing labels #遞歸調用,createTree函數 myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels) return myTree
參考:
《統計學習方法》
《機器學習實戰》
http://blog.csdn.net/jialeheyeshu/article/details/51832165








