機器學習 | 樹迴歸

由於近期學業繁重QAQ,所以我就不說廢話了,直接上代碼~

運行結果

圖片描述

圖片描述

代碼

from numpy import *
#使用二元切分法——每次將數據集切成兩份
#如果數據的某特徵值等於切分所要求的值,
#那麼這些數據就進入樹的左子樹,反之則
# 進入右子樹
def loadDataSet(fileName):
    dataMat=[]
    fr=open(fileName)
    for line in fr.readlines():
        curLine=line.strip().split('\t')
        #將每行映射成浮點數
        fltLine=list(map(float,curLine))
        dataMat.append(fltLine)
    #將文件中的所有數據都保存在同一個矩陣中
    return dataMat


#參數:數據集,待切分的特徵,該特徵的某個值
def binSplitDataSet(dataSet,feature,value):
    #將數據集合切分得到兩個子集並返回
    mat0 = dataSet[nonzero(dataSet[:,feature] > value)[0],:]
    mat1 = dataSet[nonzero(dataSet[:,feature] <= value)[0],:]

    return mat0,mat1

#建立葉結點的函數
#當chooseBestSplit函數決定不再對數據集進行切分時,將調用該regLeaf函數
#來得到葉節點的模型。在迴歸樹種,該模型其實就是目標變量的均值
def regLeaf(dataSet):
    return mean(dataSet[:,-1])

#計算誤差的函數——這裏計算的是總方差
def regErr(dataSet):
    #均方差函數var*數據集中樣本的個數=總方差
    return var(dataSet[:,-1]) * shape(dataSet)[0]

#給定某個誤差計算方法,該函數會找到數據集上最佳的二元切割方式
#(他遍歷所有的特徵及可能的取值來找到使誤差最小化的切分閾值)
#另外,該函數還要確定什麼時候停止切分,一旦停止切分就會生成一個葉節點
#errType爲平方誤差的總值(總方差)
def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):
    #用戶指定的參數,用於控制函數停止時機
    #tolS爲誤差下降值,tolN爲切分的最少樣本數
    tolS = ops[0]; tolN = ops[1]
    #如果所有值相等則退出
    if len(set(dataSet[:,-1].T.tolist()[0])) == 1:
        #找不到一個“好”的二元切分,返回None並同時調用leafType來生成葉節點
        return None, leafType(dataSet)
    m,n = shape(dataSet)
    S = errType(dataSet)
    bestS = inf; bestIndex = 0; bestValue = 0
    for featIndex in range(n-1):
        for splitVal in set((dataSet[:,featIndex].T.A.tolist())[0]): 
            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 (S - bestS) < tolS: 
        return None, leafType(dataSet) 
    mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue)
    #如果切分出的數據集很小則退出
    if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN): 
        return None, leafType(dataSet)
    #找到了一個“好”的切分方式,返回特徵編號和切分特徵值
    #找到了最佳的切分方式:切分後能達到最低誤差的切分
    return bestIndex,bestValue


#構建樹的函數
#dataSet爲數據集
#leafType爲建立葉結點的函數,errType爲誤差計算函數
#ops是一個包含書構建所需其他參數的元組
def createTree(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):
    #chooseBestSplit爲切分函數
    #若滿足停止條件chooseBestSplit將返回None和某類模型的值
    #如果構建的是迴歸樹,該模型是一個常數,如果是模型樹,其
    #模型是一個線性方程(迴歸樹假設葉節點是常數值)
    #若不滿足停止條件,chooseBestSplit將創建一個新的python
    #字典,並將數據集分成兩份,在這兩份數據集上分別繼續遞歸調
    #用createTree函數
    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


def drawFigure1():
    # import matplotlib.pyplot as plt 
    # myDat=loadDataSet('ex00.txt') 
    # myMat=mat(myDat) 
    # createTree(myMat) 
    # plt.plot(myMat[:,0],myMat[:,1],'ro') 
    # plt.show()
    import matplotlib.pyplot as plt 
    myDat=loadDataSet('ex0.txt') 
    myMat=mat(myDat) 
    createTree(myMat) 
    plt.plot(myMat[:,1],myMat[:,2],'ro') 
    plt.show()



def main():
    drawFigure1()
    # myDat=loadDataSet('ex00.txt')
    # myMat=mat(myDat)
    # myTree=createTree(myMat)
    # print(myTree)


    #建立一個主對角線元素全爲1的矩陣
    #testMat=mat(eye(4))
    #print(testMat)
    #要分割的特徵位於第一列
    #按照0.5去劃分
    #mat0,mat1=binSplitDataSet(testMat,0,0.5)
    # print(mat0)
    # print(mat1)

if __name__=='__main__':
    main()```


  [1]: /img/bVbqGCZ
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章