机器学习经典算法8-树回归

原创 2013年08月19日 09:18:49

1.简单介绍

        线性回归方法可以有效的拟合所有样本点(局部加权线性回归除外)。当数据拥有众多特征并且特征之间关系十分复杂时,构建全局模型的想法一个是困难一个是笨拙。此外,实际中很多问题为非线性的,例如常见到的分段函数,不可能用全局线性模型来进行拟合。

树回归将数据集切分成多份易建模的数据,然后利用线性回归进行建模和拟合。这里介绍较为经典的树回归CART(classification and regression trees,分类回归树)算法。

2.分类回归树基本流程

    构建树:

           1.找到[最佳待切分特征]

            2.若不能再切分,则将该节点存为[叶子节点]并返回

            3.按照最佳待切分特征将数据集切分成左右子树(这里为了方便,假设大于特征值则为左,小于则归为右)

            4.对左子树进行[构建树]

            5.对右子树进行[构建树]

   最佳待切分特征:

           1.遍历特征

               1.1遍历特征所有特征值

                    1.1.1计算按该特征值进行数据集切分的[误差]

           2.选择误差最小的特征及其相应值作为最佳待切分特征并返回

   基于回归树的预测:

           1.判断当前回归树是否为叶子节点,如果是则[预测],如果不是则执行2

            2.将测试数据相应特征上的特征值与当前回归树进行比较,如果测试数据特征值大,则判别当前回归树的左子树是否为叶子节点,如果不是叶子节点则进行[基于回归树的预测],如果是叶子节点,则[预测];反之,判别当前回归树的右子树是否为叶子节点,如果不是叶子节点则进行[基于回归树的预测],如果是叶子节点,则[预测]

3.分类回归树的实践说明

  

        误差、叶子节点和预测三者有相关的关联关系,一种相对简单的是误差采用的是y值均方差,叶子节点相应的建立为该节点下所有样本的y值平均值,预测的时候根据判断返回该叶子节点下y值平均值即可。

        在进行最佳待切分特征选取的时候,一般还有两个参数,一个是允许的误差下降值,一个是切分最小样本数。对于允许误差下降值,在实际过程中,需要在分割之后其误差减少应该至少大于该bound;对于切分最小样本数,也就是说切分后的子树中包含的样本数应该多于该bound。其实这两种策略都是为了避免过拟合。

4树剪枝

       

        通过在最佳待切分特征选取时进行参数设定来避免过拟合,这其实是一种预剪枝的行为;而在回归树建立后,再进行剪枝,则是一种后剪枝的行为。

        后剪枝的过程如下:

               如果存在任一子集是一棵树,则在该子集中递归剪枝

               计算当前两个叶子节点合并后的误差

               计算不合并的误差

              比较合并前后误差,如果合并后的误差降低,则对叶子节点进行合并

5模型树

        之前讲到误差、叶子节点和预测三者具备关联关系,当建立叶子节点是基于模型的,则构建了相应的模型树。这里可以使用之前的线性回归模型,建立相应的叶子节点。这样误差计算采用的将是线性回归中的误差,而预测则是基于该叶子节点拟合其样本后的参数。

6编程实现

         这里createTree负责进行树的构建;chooseBestSplit函数负责进行最佳带切特征的选取,而ops参数则是进行了两个bound的设定;prune进行了相关后剪枝。
         这里regErr、regLeaf、regTreeEval是基于简单均值计算的误差、叶子节点和预测;而modelErr、modelLeaf和modelTreeEval(+linearSolve)则是基于线性回顾模型的误差、叶子节点和预测。
         数据集链接:http://pan.baidu.com/share/link?shareid=3744521160&uk=973467359 密码:9ivd
from numpy import *
def loadDataSet(filename):
    dataMat = []
    fr = open(filename)
    for line in fr.readlines():
        curLine = line.strip('\n').split('\t')
        fltLine = map(float, curLine)
        dataMat.append(fltLine)
    fr.close()
    return dataMat
def regLeaf(dataSet):
    return mean(dataSet[:,-1])
def regErr(dataSet):
    return var(dataSet[:,-1])*shape(dataSet)[0]
def regTreeEval(model, inDat):
    return float(model)
def linearSolve(dataSet):
    m,n=shape(dataSet)
    X = mat(ones((m,n)))
    Y = mat(ones((m,1)))
    X[:,1:n]=dataSet[:,0:n-1]
    Y=dataSet[:,-1]
    xTx = X.T*X
    if linalg.det(xTx)==0.0:
        raise NameError('This matrix is singular, cannot do inverse, \
               try increasing the second value of ops')
    ws = xTx.T*(X.T*Y)
    return ws, X, Y
def modelLeaf(dataSet):
    ws, X, Y = linearSolve(dataSet)
    return ws
def modelErr(dataSet):
    ws,X,Y = linearSolve(dataSet)
    yHat = X*ws
    return sum(power(Y-yHat,2))
def modelTreeEval(model, inDat):
    n=shape(inDat)[1]
    X = mat(ones((1,n+1)))
    X[:,1:n+1]=inDat
    return float(X*model)
def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):
    tolS = ops[0]
    tolN = ops[1]
    if len(set(dataSet[:,-1].T.tolist()[0])) == 1:
        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]):
            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):
        print "Not enough nums"
        return None, leafType(dataSet)
    return bestIndex, bestValue
def binSplitDataSet(dataSet, feature, value):
    mat0 = dataSet[nonzero(dataSet[:, feature]>value)[0],:][0]
    mat1 = dataSet[nonzero(dataSet[:, feature]<=value)[0],:][0]
    return mat0, mat1
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
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 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 not isTree(tree['right']) and not isTree(tree['left']):
        lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])
        errorNoMerge = sum(power(lSet[:,-1]-tree['left'],2))+\
                       sum(power(rSet[:,-1]-tree['right'],2))
        treeMean = (tree['left']+tree['right'])/2.0
        errorMerge = sum(power(testData[:,-1]-treeMean,2))
        if errorMerge < errorNoMerge:
            print "Merging"
            return treeMean
        else:
            return tree
    else:
        return tree
def treeForeCast(tree, inData, modelEval=regTreeEval):
    if not isTree(tree):
        return modelEval(tree, inData)
    if inData[tree['spInd']]>tree['spVal']:
        if isTree(tree['left']):
            return treeForeCast(tree['left'], inData, modelEval)
        else:
            return modelEval(tree['left'],inData)
    else:
        if isTree(tree['right']):
            return treeForeCast(tree['right'], inData, modelEval)
        else:
            return modelEval(tree['right'], inData)
def createForeCast(tree, testData, modelEval=regTreeEval):
    m=len(testData)
    yHat = mat(zeros((m,1)))
    for i in range(m):
        yHat[i,0]=treeForeCast(tree, mat(testData[i]), modelEval)
    return yHat
'''
myData2 = loadDataSet(r"ex2.txt")
myMat2 = mat(myData2)
tree2 = createTree(myMat2, ops=(0,1))
print tree2
myData2Test = loadDataSet(r"ex2test.txt")
myMat2Test = mat(myData2Test)
print prune(tree2, myMat2Test)
'''
trainMat = mat(loadDataSet('bikeSpeedVsIq_train.txt'))
testMat = mat(loadDataSet('bikeSpeedVsIq_test.txt'))
myregTree=createTree(trainMat, ops=(1,20))
mymodTree=createTree(trainMat, modelLeaf, modelErr, (1,20))
yregHat=createForeCast(myregTree, testMat[:,0])
ymodHat=createForeCast(mymodTree, testMat[:,0], modelTreeEval)
regCo = corrcoef(yregHat, testMat[:,1], rowvar=0)[0,1]
modCo = corrcoef(ymodHat, testMat[:,1], rowvar=0)[0,1]
print "reg", regCo
print "model", modCo


相关文章推荐

数据挖掘十大经典算法--CART: 分类与回归树

一、决策树的类型  在数据挖掘中,决策树主要有两种类型: 分类树 的输出是样本的类标。 回归树 的输出是一个实数 (例如房子的价格,病人呆在医院的时间等)。 术语分类和回归树 (CART) 包含了...

简单易学的机器学习算法——分类回归树CART

一、树回归的概念 二、

CART分类回归树

这一篇主要是CART,有几个重点的词语先写下来,重点哦:基尼指数(Gini index,跟经济学的基尼系数长这么像,八杆子打得着吗)、最小二乘回归树(least squares regression ...
  • learnee
  • learnee
  • 2015年11月20日 23:03
  • 4333

分类树和回归树的区别

分类树 以C4.5分类树为例,C4.5分类树在每次分枝时,是穷举每一个feature的每一个阈值,找到使得按照feature阈值分成的两个分枝的熵最大的阈值(熵最大的概念可理解成尽可能每个分枝的男女...

CART分类与回归树的原理与实现

CART(Classification And Regression Tree)算法采用一种二分递归分割的技术,将当前的样本集分为两个子样本集,使得生成的的每个非叶子节点都有两个分支。因此,CART算...

从回归树到GBDT

GBDT可以看做是由多棵回归树组成的,所以要理解GBDT,就要先理解回归树。回归树也是为了做预测,只是将特征空间划分成了若干个区域,在每个区域里进行预测。...
  • zqxnum1
  • zqxnum1
  • 2015年03月17日 20:28
  • 2120

[完]机器学习实战 第九章 树回归

将数据集切分成很多份易建模的数据,然后利用线性回归技术建模。如果首次切分后仍难以拟合线性模型就继续切分,在这种切分模式下,树结构和回归法相当有用。CART(分类回归树)算法,用于构建二元树并处理离散型...

机器学习经典算法详解及Python实现--CART分类决策树、回归树和模型树

Classification And Regression Tree(CART)是一种很重要的机器学习算法,既可以用于创建分类树(Classification Tree),也可以用于创建回归树(Reg...

树模型之回归树,模型树,树剪枝

在前面决策树的介绍中,我们使用ID3算法来构建决策树;这里我们使用CART算法来构建回归树和模型树。ID3算法是每次选取当前最佳的特征来分割数据,并按照该特征的所有可能取值来区分。比如,如果一个特征有...

机器学习理论与实战(九)回归树和模型树

前一节的回归是一种全局回归模型,它设定了一个模型,不管是线性还是非线性的模型,然后拟合数据得到参数,现实中会有些数据很复杂,肉眼几乎看不出符合那种模型,因此构建全局的模型就有点不合适。这节介绍的树回归...
  • cuoqu
  • cuoqu
  • 2013年07月27日 00:29
  • 9773
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:机器学习经典算法8-树回归
举报原因:
原因补充:

(最多只允许输入30个字)