決策樹分爲分類決策樹和迴歸決策樹:html
上一篇介紹了分類決策樹以及Python實現分類決策樹: 監督學習——決策樹理論與實踐(上):分類決策樹算法
決策樹是一種依託決策而創建起來的一種樹。在機器學習中,決策樹是一種預測模型,表明的是一種對象屬性與對象值之間的一種映射關係,每個節點表明某個對象/分類,樹中的每個分叉路徑表明某個可能的屬性值,而每個葉子節點則對應從根節點到該葉子節點所經歷的路徑所表示的對象的值數據結構
經過訓練數據構建決策樹,能夠高效的對未知的數據進行分類。決策數有兩大優勢:1)決策樹模型能夠讀性好,具備描述性,有助於人工分析;2)效率高,決策樹只須要一次構建,反覆使用,每一次預測的最大計算次數不超過決策樹的深度。app
決策樹是一顆樹形的數據結構,能夠是多叉樹也能夠是二叉樹,決策樹其實是一種基於貪心策略構造的,每次選擇的都是最優的屬性進行分裂。less
決策樹也是一種監督學習算法,它的樣本是(x,y)形式的輸入輸出樣例。機器學習
迴歸樹:函數
相對於上一篇所講的決策樹,這篇所講的迴歸樹主要解決迴歸問題,因此給定的訓練數據輸入和標籤都是連續的。學習
CART算法的思路是將特徵空間切分爲m個不一樣的子空間,經過測試數據(落在每一個子空間中的測試數據)來計算每一個子空間的輸出值(對應下式中的Cm)。當這樣的空間幾何生成以後就能夠很方便的將一個未知數據映射到某一個子空間Ri中,將Ci的值做爲該未知數據的輸出值。測試
這裏Cm的取值通常採用均值算法,即取全部落在該子空間的測試數據的均做爲該子空間的值:優化
這裏確定會涉及到一個,這也是CART算法的關鍵: 如何去劃分一個一個子空間?如何去選擇第j個變量Xj和它取值s做爲切分變量和切分點,並定義成兩個區域。這裏《統計學方法》中給出了算法思路:
算法實現時,比那裏全部切分向量,切分點是測試數據在Xj上的全部取值集合。經過5.19就能計算出當前最佳的切分向量j和切分點x以及劃分紅的兩個區域的取值c1,c2。(該部分的Python實現對應下文中chooseBestSplit函數)
當對一個總體測試數據調用上面邏輯後會獲得一個j和x值,經過這兩個值將空間分紅了兩個空間,再分別對兩個子空間調用上面的邏輯,這樣遞歸下去就能生成一棵決策樹。(對應下文中createTree函數)
CART剪枝算法從「徹底生長」的決策樹的底端減去一些子樹,使決策樹變小(模型變簡單),從而可以對未知數據有更準確的預測。
後續待補充
加載測試數據,以及測試數據的值(X,Y),這裏數據和值都存放在一個矩陣中。
def loadDataSet(fileName): #general function to parse tab -delimited floats dataMat = [] #assume last column is target value fr = open(fileName) for line in fr.readlines(): curLine = line.strip().split('\t') fltLine = map(float,curLine) #map all elements to float() dataMat.append(fltLine) return dataMat
該函數用於切分數據集,將測試數據某一列中的元素大於和小於的測試數據分開,分別放到兩個矩陣中:
def binSplitDataSet(dataSet, feature, value): mat0 = dataSet[nonzero(dataSet[:,feature] > value)[0],:][0] mat1 = dataSet[nonzero(dataSet[:,feature] <= value)[0],:][0] return mat0,mat1
輸入參數 feature 爲指定的某一列
value爲切分點的值,經過該該值將dataset一份爲二
這裏涉及到三個函數,分別在代碼註釋中進行了說明,真正計算最優值的函數爲最後一個。
# 葉節點值計算函數: 這裏以均值做爲葉節點值 def regLeaf(dataSet):#returns the value used for each leaf return mean(dataSet[:,-1]) # 預測偏差計算函數:這裏用均方差表示 def regErr(dataSet): return var(dataSet[:,-1]) * shape(dataSet)[0] # 遍歷每一列中每一個value值,找到最適合分裂的列和切分點 def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)): tolS = ops[0]; # 均方差最小優化值,若是大於該值則沒有必要切分 tolN = ops[1] # 須要切分數據的最小長度,若是已經小於該值,則無需再切分 #if all the target variables are the same value: quit and return value if len(set(dataSet[:,-1].T.tolist()[0])) == 1: #exit cond 1 return None, leafType(dataSet) m,n = shape(dataSet) #the choice of the best feature is driven by Reduction in RSS error from mean S = errType(dataSet) bestS = inf; bestIndex = 0; bestValue = 0 for featIndex in range(n-1): for splitVal in set(dataSet[:,featIndex]): mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal) if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN): continue newS = errType(mat0) + errType(mat1) if newS < bestS: bestIndex = featIndex bestValue = splitVal bestS = newS #if the decrease (S-bestS) is less than a threshold don't do the split if (S - bestS) < tolS: return None, leafType(dataSet) #exit cond 2 mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue) if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN): #exit cond 3 return None, leafType(dataSet) return bestIndex,bestValue#returns the best feature to split on #and the value used for that split
在上面函數基礎之上,建立一個迴歸樹也就不難了:
def createTree(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):#assume dataSet is NumPy Mat so we can array filtering feat, val = chooseBestSplit(dataSet, leafType, errType, ops)#choose the best split if feat == None: return val #if the splitting hit a stop condition return val retTree = {} retTree['spInd'] = feat retTree['spVal'] = val lSet, rSet = binSplitDataSet(dataSet, feat, val) retTree['left'] = createTree(lSet, leafType, errType, ops) retTree['right'] = createTree(rSet, leafType, errType, ops) return retTree
這裏是一個遞歸調用,須要注意函數的終止條件,這裏當數據集不能再分時纔會觸發終止條件,實際中這種操做頗有可能會出現過擬合,能夠認爲地加一些終止條件進行「預剪枝」。
參考:
《機器學習實戰》
《統計學習方法》