由於近期學業繁重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