机器学习 | 树回归
由于近期学业繁重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