树回归

当数据拥有众多特征并且特征之间关系十分复杂时,构建全局模型的想法就显得太难了。实际生活中很多问题都是非线性的,不可能使用全局性模型来拟合任何数据。

一种可行的方法就是将数据集切分成很多易建模的数据,然后再利用线性回归技术来建模。本章介绍一种新的叫做CART的树构建算法,该算法可用于分类也可用于回归。

复杂数据的局部性建模

树构建算法:

  • ID3 每次选取当前最佳的特征来分割数据,并按照该特征的所有可能取值来切分。如果一个特征有4个取值,那么数据将被切分成4份。一旦按某特征切分后,该特征在之后的算法执行中将不会再起作用。
  • 二分法 每次把数据切成两份。如果特征值大于给定值就走左子树,否则就走右子树。
    CART使用二元切分来处理连续型变量。对CART稍作修改就可以处理回归问题。

在树的构建过程中,需要解决多种类型数据的存储问题。这里使用字典来存储树的数据结构,字典包括1、待切分的特征 2、待切分的特征值。 3、右子树。当不再需要切分的时候也可以是单个值。4、左子树。 与右子树类似。

'''
创建树节点
'''
class treeNode():
    def __init__(self,feat,val,right,left):
        self.featureToSplitOn = feat
        self.valueOfSpit = val
        self.rightBranch = right
        self.leftBranch = left
'''
加载数据
'''
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

'''
构建树  
dataSet 数据集
leafType 建立叶子节点的函数
errType  代表误差计算函数
ops 代表树构建所需其他参数的元组
'''
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 = bindSplitDataSet(dataSet,feat,val)
    retTree['left'] = createTree(lSet,leafType,errType,ops)
    retTree['right'] = createTree(rSet,leafType,errType,ops)
    return retTree


'''
负责生成叶子节点 当chooseBestSplit确定不再对数据进行切分时,调用子方法得到叶子节点
该函数就是目标变量的均值
'''
def regLeaf(dataSet):
    return mean(dataSet[:,-1])

'''
在给定数据上计算目标变量的平均误差
'''
def regErr(dataSet):
    return var(dataSet[:,-1]) * shape(dataSet)[0]

'''
三个参数 分别为数据集合,待切分的特征和该特诊的某个值
'''
def bindSplitDataSet(dataSet,feature,value):
    mats0 = dataSet[nonzero(dataSet[:,feature] > value)[0],:]
    mats1 = dataSet[nonzero(dataSet[:,feature] <= value)[0],:]
    mat0 = [];mat1 = []
    if len(mats0) > 1:mat0 = mats0
    if len(mats1) > 1:mat1 = mats1
    return mat0,mat1

'''
找到最佳二元切分
dataSet 数据集
leafType 建立叶子节点的函数
errType  代表误差计算函数
ops 代表树构建所需其他参数的元组
'''
def chooseBestSplit(dataSet,leafType=regLeaf,errType = regErr,ops=(1,4)):
    #ops的两个值  用于控制函数的退出机制
    #tolS容许的误差下降值
    #tolN切分的最好样本
    tolS = ops[0];tolN = ops[1]
    #如果所有值相等则退出   如果该数目为1 就不需要再切分了
    if len(set(dataSet[:,-1].T.tolist()[0])) == 1:
        return None,leafType(dataSet)
    m,n = shape(dataSet)
    S = errType(dataSet)
    bestS = inf; bestIndx = 0; bestValue = 0
    # 在所有可能的特征和可能取值上遍历
    #最佳的切分就是切分后能达到最低误差的切分
    for featIndex in range(n-1):
        #书中源代码有错误。
        for splitVal in set(dataSet[:,featIndex].T.A.tolist()[0]):
            mat0,mat1 = bindSplitDataSet(dataSet,featIndex,splitVal)
            if(shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN):continue
            newS = errType(mat0) + errType(mat1)
            if newS < bestS:
                bestIndx = featIndex
                bestValue = splitVal
                bestS = newS
    #如果误差减少不大则退出
    if(S - bestS) < tolS:
        return None,leafType(dataSet)
    mat0,mat1 = bindSplitDataSet(dataSet,bestIndx,bestValue)
    #如果切分的数据小则退出
    if(shape(mat0)[0] < tolN) or (shape(mat1)[0]<tolN):
        return None,leafType(dataSet)
    return bestIndx,bestValue


if __name__ == '__main__':
    myDat = loadDataSet('eex00.txt')
    myMat = mat(myDat)
    retTree = createTree(myMat)
    print(retTree)

>>> {'left': 1.0180967672413792, 'spVal': 0.48813, 'spInd': 0, 'right': -0.044650285714285719}



if __name__ == '__main__':
    myDat = loadDataSet('regTreesex0.txt')
    myMat = mat(myDat)
    retTree = createTree(myMat)
    print(retTree)
>>> {'right': {'right': -0.023838155555555553, 'left': 1.0289583666666666, 'spInd': 1, 'spVal': 0.197834},
'left': {'right': 1.980035071428571, 'left': {'right': 2.9836209534883724, 'left': 3.9871631999999999, 'spInd': 1, 'spVal': 0.797583}, 'spInd': 1, 'spVal': 0.582002}, 'spInd': 1, 'spVal': 0.39435}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 第9章 树回归 树回归 概述 我们本章介绍 CART(Classification And Regression ...
    Joyyx阅读 1,130评论 0 3
  • 一、树回归介绍 线性回归包含了一些强大的方法,但这些方法创建的模型需要拟合所有的样本点(局部加权线性回归除外)。当...
    nobodyyang阅读 553评论 0 0
  • 姓名:唐来宾 学号:17101223417 转载http://mp.weixin.qq.com/s/-CSSh2p...
    ahbz_t阅读 1,350评论 1 4
  • 前一章介绍了线性回归有很多强大的方法,但是缺点是创建的模型需要拟合所有的样本点(局部加权线性回归除外),当数据拥有...
    1597830b3381阅读 544评论 0 0
  • 在上一篇文章中,我们比较全面地学习了线性回归的原理是实现,今天我们还是留在回归板块,针对树回归进行学习和实践。 0...
    Sudden阅读 1,619评论 0 1