CART算法的樹回歸:
返回的每個節點最后是一個最終確定的平均值。
#coding:utf-8 import numpy as np # 加載文件數據 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 #在dataset中選擇特征為feature的這一列,以value值分成兩部分 def binSplitDataSet(dataSet, feature, value): mat0 = dataSet[np.nonzero(dataSet[:,feature] > value)[0],:][0] mat1 = dataSet[np.nonzero(dataSet[:,feature] <= value)[0],:][0] return mat0,mat1 #計算此矩陣的最后一列結果的平均值,用平均值來當做最后的返回結果,后面的模型樹返回的是一個 線性模型 def regLeaf(dataSet): return np.mean(dataSet[:,-1]) #計算dataset結果的混亂程度,用方差反應,因為是連續數據 def regErr(dataSet): return np.var(dataSet[:,-1]) * np.shape(dataSet)[0] #選擇最佳的分離特征和該特征的分離點 #這里的ops是預先的給定值,1是差別太小就不分了,4是分開后的各自樣本數,太小就舍去,這是一 種預剪枝方法 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 = np.shape(dataSet) #the choice of the best feature is driven by Reduction in RSS error from mean S = errType(dataSet) bestS = np.inf; bestIndex = 0; bestValue = 0 #循環所有的特征 for featIndex in range(n-1): #循環該特征下的所有特征值 for splitVal in set(dataSet[:,featIndex]): mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal) #如果更具這個特征值分成的兩類有一個小與預先給定值,說明分類太偏,則不考慮 if (np.shape(mat0)[0] < tolN) or (np.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 (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN): #exit cond 3 return None, leafType(dataSet) return bestIndex,bestValue #創建樹 def createTree(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)): feat, val = chooseBestSplit(dataSet, leafType, errType, ops) if feat == None: 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 myDat = loadDataSet('ex0.txt') myMat = np.mat(myDat) result = createTree(myMat) print result
結果:
{'spInd': 1, 'spVal': matrix(` 0`.`39435`), 'right': {'spInd': 1, 'spVal': matrix(` 0`.`197834`), 'right': -0.023838155555555553, 'left': 1.0289583666666666}, 'left': {'spInd': 1, 'spVal': matrix(` 0`.`582002`), 'right': 1.980035071428571, 'left': {'spInd': 1, 'spVal': matrix(` 0`.`797583`), 'right': 2.9836209534883724, 'left': 3.9871631999999999}}}
結果的意思是:第幾個特征,以多大作為特征值分開,分成左右,依次分下去。
這個算法很好,但是對數據的分類太過于高,容易造成過擬合。因此要采用剪枝技術。
通過降低決策樹的復雜度來避免過擬合的過程稱為剪枝。
#判斷obj是否是一個子樹 def isTree(obj): return (type(obj).__name__=='dict') #用于坍塌處理,當測試數據集是空是,則取整個樹的平均值 def getMean(tree): if isTree(tree['right']): tree['right'] = getMean(tree['right']) if isTree(tree['left']): tree['left'] = getMean(tree['left']) return (tree['left']+tree['right'])/2.0 #剪枝函數 def prune(tree, testData): #如果測試數據集為空,則坍塌處理 if np.shape(testData)[0] == 0: return getMean(tree) #如果左或者右是樹,則把測試數據集根據決策樹進行分割 if (isTree(tree['right']) or isTree(tree['left'])): lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal']) #如果左側是樹,則把數據集和子樹帶入繼續找 if isTree(tree['left']): tree['left'] = prune(tree['left'], lSet) #同理 if isTree(tree['right']): tree['right'] = prune(tree['right'], rSet) #if they are now both leafs, see if we can merge them #如果左右都是節點,則計算節點誤差 if not isTree(tree['left']) and not isTree(tree['right']): lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal']) #計算不合并的誤差 errorNoMerge = sum(np.power(lSet[:,-1] - tree['left'],2)) + sum(np.power(rSet[:,-1] - tree['right'],2)) treeMean = (tree['left']+tree['right'])/2.0 #計算將當前兩個葉子節點合并后的誤差 errorMerge = sum(np.power(testData[:,-1] - treeMean,2)) if errorMerge < errorNoMerge: print "merging" #可以合并就返回平均值 return treeMean #不可以合并就返回樹,不變 else: return tree else: return tree
一般來說都是預剪枝和后剪枝合并使用
模型樹
每個節點是一個線性模型
其他基本一樣:
#對數據集進行線性回歸 def linearSolve(dataSet): m,n = np.shape(dataSet) X = np.mat(np.ones((m,n))); Y = np.mat(np.ones((m,1))) #有一列是常數項,因此要多出一列放置常數項 X[:,1:n] = dataSet[:,0:n-1]; Y = dataSet[:,-1] xTx = X.T*X if np.linalg.det(xTx) == 0.0: raise NameError('This matrix is singular, cannot do inverse,\n\ try increasing the second value of ops') ws = xTx.I * (X.T * Y) return ws,X,Y #產生針對該數據集的線性模型 #相當于上面的regLeaf函數 def modelLeaf(dataSet): ws,X,Y = linearSolve(dataSet) return ws #產生針對該數據集的線性模型,并計算誤差返回 #相當于上面的regErr函數,計算模型的誤差,如果分后和不分的誤差差不多則選擇不分 def modelErr(dataSet): ws,X,Y = linearSolve(dataSet) yHat = X * ws return sum(np.power(Y - yHat,2))
模型樹回歸很好,而且可以用作預測
另外有需要云服務器可以了解下創新互聯scvps.cn,海內外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業上云的綜合解決方案,具有“安全穩定、簡單易用、服務可用性高、性價比高”等特點與優勢,專為企業上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。
文章標題:學習日志---樹回歸(回歸樹,模型樹)-創新互聯
鏈接URL:http://vcdvsql.cn/article28/eiicp.html
成都網站建設公司_創新互聯,為您提供ChatGPT、網頁設計公司、營銷型網站建設、網站設計、網站改版、面包屑導航
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯