机器学习算法之 树回归


 上一章介绍的线性回归,创建的模型需要拟合所有样本点(局部加权线性回归除外)。当数据拥有众多特征并且特征之间关系

十分复杂时,构建全局模型的就非常困难,且实际生活中很多问题都是非线性的,不可能使用全局线性模型来拟合任何数据。

 那么有一种方法,将数据集切分成很多份容易建模的数据,然后利用线性回归技术来建模,如果切分后仍然难以模拟线性模型

就继续切分。这种切分方式,树结构和回归的结合。

 本章介绍两种回归树和模型树两种树构建算法:

  回归树(regression tree) 其每个节点包含单个值

  模型树(model tree) 其每个节点包含一个线性方程

1 回归树

复杂数据的局部性建模:
 前面介绍的决策树,做法是每次选取当前最佳的特征来分割数据,并按照该特征的所有可能取值来切分。比如特征有4种取值,

那么数据分成4份。且按某特征切分后,该特征无法再起作用。所有观点认为这个切分过于迅速。除外决策树不能直接处理连续性特征,

必须先把连续型特征转化成离散型。这样会破坏连续型特征。

 而本章使用树构建过程为二元切分法:如果特征值大于给定的数据走左子树,否则就走右子树。下面介绍使用广泛的树构建

算法CART

1.1CART

 CART(Classification And Regression Trees,分类回归树),该算法即可以用于分类还可以用于回归,后面再看树减枝技术

(主要目的是防止树的过拟合)

 CART使用的二元切分方法,createtree()的大致伪代码如下:

 找到最佳待切分特征

  如果该节点不能再分,将该节点存为叶节点

  执行二元切分

  在右子树调动createtree函数

  在左子树调动createtree函数

代码
代码说明:

loadDataSet - 构建数据集,该函数读取一个tab键为分隔符的文件,将每行内容保存成一组浮点数。

binSplitDataSet - 指定特征及阈值把一个矩阵分成两个

createTree - 创建一个数,递归函数。先找到最佳分类特征(chooseBestSplit),按特征值阈值一分二,构建左子树和右子树。直到

无法分为止。

regLeaf - 负责生成叶子节点,chooseBestSplit确定不再数据进行分割时调用该函数来得到叶节点的模型。在回归树中,即取目标

变量(y)的均值。用于预测测试目标的值。

chooseBestSplit - 寻找最佳分类特征及阈值,其中参数tolS和tolN 用于控制函数的停止时机。tolS为是允许的误差下降值,tolN是切分

的最小样本数。思路如下:
在这里插入图片描述
regErr - 给定数据上目标变量的平方误差

from numpy import *

def loadDataSet(fileName):      #general function to parse tab -delimited floats
    dataMat = []                #assume last column is target value
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        fltLine = map(float,curLine) #map all elements to float()
        dataMat.append(fltLine)
    return dataMat

def binSplitDataSet(dataSet, feature, value):
    mat0 = dataSet[nonzero(dataSet[:,feature] > value)[0],:]
    mat1 = dataSet[nonzero(dataSet[:,feature] <= value)[0],:]
    #print mat0,mat1
    return mat0,mat1

def regLeaf(dataSet):#returns the value used for each leaf
    return mean(dataSet[:,-1])

def regErr(dataSet):
    return var(dataSet[:,-1]) * shape(dataSet)[0]

def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):
    tolS = ops[0]; tolN = ops[1]
    #if all the target variables are the same value: quit and return value
    if len(set(dataSet[:,-1].T.tolist()[0])) == 1: #exit cond 1
        return None, leafType(dataSet)
    m,n = shape(dataSet)
    #the choice of the best feature is driven by Reduction in RSS error from mean
    S = errType(dataSet)
    bestS = inf; bestIndex = 0; bestValue = 0
    for featIndex in range(n-1):
        for splitVal in set((dataSet[:,featIndex].T.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 the decrease (S-bestS) is less than a threshold don't do the split
    if (S - bestS) < tolS: 
        return None, leafType(dataSet) #exit cond 2
    mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue)
    if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN):  #exit cond 3
        return None, leafType(dataSet)
    return bestIndex,bestValue#returns the best feature to split on
                              #and the value used for that split

1.2 减枝算法

 上面提到过如果树节点过多,可能会过拟合。通过降低树的复杂度来避免过拟合称为剪枝(pruning)。其实前面构建树时已经

使用过,chooseBestSplit 中止条件tolS和tolN是一种所谓的预剪枝操作。另一种形式的剪枝需要测试集和训练集,称作为后剪枝。


后减枝算法
 原理是先用训练数据建立一个最复杂的回归树(误差为0,叶子节点分到每一个数值)。然后从上而下找到叶节点,用测试数据来

判断将这些叶节点合并后是否降低误差,如果是的话合并。

伪代码如下:

 基于已有的树切分测试数据:

  如果存在任意子集是一棵树,则再该子集递归剪枝过程

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

  计算不合并的误差

  如果合并会降低误差的话,就将叶节点合并

2 模型树

 节点不是简单的数值,取代的是一些线性模型

 区别就是叶子节点不是数值,一个线性函数,modelLeaf,算法使用回顾算法中的
在这里插入图片描述
误差算法:平方误差

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值