个人觉得线性回归和树回归问题,都比想象中要复杂,值得探索。树回归的理论部分不难,不过徒手写树回归算法倒是需要琢磨。
另: 线性回归和树回归的理论部分在整理中
普通回归树与模型回归树的比较
说明:
将 bikeSpeedVsIq_train.txt
和 bikeSpeedVsIq_test.txt
放在当前目录下。
from numpy import *
import matplotlib.pyplot as plt
普通回归树的叶节点生成函数
"""
第一个函数是regLeaf(),它负责生成叶节点。当chooseBestSplit()
函数确定不再对数据进行切分时,将调用该regLeaf()函数来得到叶节点的模型。在回归树中,
该模型其实就是目标变量的均值。
"""
def regLeaf(dataSet):#returns the value used for each leaf
return mean(dataSet[:,-1])
#因为这里需要返回的是总方差,所以要用均方差乘以数据集中样本的个数。计算总方差。均方误差*样本数目
def regErr(dataSet):
return var(dataSet[:,-1]) * shape(dataSet)[0]
模型回归树的叶节点生成函数
"""
与回归树的做法(在每个叶节点上使用各自的均值做预测)不同,该算法需要在每个叶节点上都构建出一个线性模型
"""
#第一个函数是linearSolve(),它会被其他两个函数调用。其主要功能是将数据集格式化成目标变量Y和自变量X
def linearSolve(dataSet): #helper function used in two places
m,n = shape(dataSet)
#数据集矩阵的第一列初始化为1,偏置项;每个样本目标变量值存入Y
X = mat(ones((m,n))); Y = mat(ones((m,1)))
X[:,1:n] = dataSet[:,0:n-1]; Y = dataSet[:,-1]#and strip out Y
xTx = X.T*X
if 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
#第二个函数modelLeaf()与函数regLeaf()类似,当数据不再需要切分的时候它负责生成叶节点的模型。该函数在数据集上调用linearSolve()并返回回归系数ws。
def modelLeaf(dataSet):
ws,X,Y = linearSolve(dataSet)
return ws
#最后一个函数是modelErr(),可以在给定的数据集上计算误差。它与函数regErr()类似,
#会被chooseBestSplit()调用来找到最佳的切分。该函数在数据集上调用linearSolve(),之后返回yHat和Y之间的平方误差。
def modelErr(dataSet):
ws,X,Y = linearSolve(dataSet)
yHat = X * ws
return sum(power(Y - yHat,2))