CART树回归

来源:互联网 发布:whatsapp for mac 编辑:程序博客网 时间:2024/05/14 12:31

决策树生成涉及到两个问题:如何选择最优特征属性进行分裂,以及停止分裂的条件是什么
1、树回归比线性回归强大在哪儿?
①线性回归创建的模型需要拟合所有的样本点(局部加权线性回归外)。当数据的特征众多、特征关系复杂时,构建全局模型难以实现;
②实际问题不可能都是线性的,不可能用全句线性模型来拟合任何数据;
③可以将数据切分成为易建模的多份数据,然后再利用线性回归技术来进行建模。如果首次切分后仍然难以拟合线性模型,就继续进行切分。在这种情况下,树结构和回归法就相当有用

2、树回归的优缺点:
①优点:可以对复杂和非线性的数据进行建模;
②缺点:结果不易理解;
③适用数据类型:数值型和标称型数据

3、与ID3等相比,CART中二元切分的特点
①ID3选取当前最佳特征来切分数据,并且按照该特征的所有取值来进行切分,切分速度过于迅速;
②ID3不能直接处理连续型特征,只有事先将连续型转换为离散型,才能在ID3中使用,但这种转换肯定会破坏连续型变量的内在性质,CART中的二元切分方式易于对树构建过程进行调整以处理连续型特征;
③二元切分节省了树的构建时间

4、CART回归树生成
假设XY 分别为输入、输出变量,并且Y 为连续变量,给定训练数据集

D={(x1,y1),(x2,y2),...,(xn,yn)}

考虑如何生成回归树。
一个回归树应该对应着输入空间(即特征空间)的一个划分以及在划分的单元上的输出值。假设已经将输入空间划分为M个单元R1,R2,...,RM,并且在每一个单元Rm 上有一个固定的输出值cm, 于是回归树模型可以表示为
f(x)=m=1McmI(xRm)

当输入空间的划分确定时,可以用f(x)=xiRm(yif(xi))2 来表示回归树对于训练数据的预测误差,用平方误差最小的准则来求解每个单元上的最优输出值,单元Rm 上的cm 最优值cm^Rm 上所有输入实例xi 对应的输出yi 的均值。
怎样对输入空间进行划分?
选择第j个变量x(j)s,
R1(j,s)={x|x(j)s}R2(j,s)={x|x(j)>s}

然后寻找最优切分变量j和最优且分点s,具体地,求解
minj,s[minc1xiR1(j,s)(yici)2+minc1xiR2(j,s)(yic2)2]

对固定输入变量j可以找到最优且分点s.
遍历所有输入变量,找到最优的切分变量j,构成(j,s),依次将输入空间划分为两个区域。接着对每个区域重复上述划分过程,直到满足停止条件。这样就生成了一颗回归树

5、对混乱程度的理解
为成功构建以分段常熟为叶结点的树,需要度量出数据的一致性。使用树进行分类时,会在给定节点上计算数据的混乱度。如何计算连续值的混乱度?
①首先计算所有数据的均值;
②然后计算每条数据的值到均指的差值;
③一般使用绝对值或者平方值来代替上述差值,此种做法类似于统计学中的方差计算,唯一不同的是,方差是平方误差的均值,而此处为平方误差的总值(总误差)。
*混乱程度!不是错误…*

6、回归树实例

7、代码实现
加载数据;
依据某个特征A,此特征A的某个取值a进行数据集的切分,返回根据此规则切分后,分别生成的两个数据集mat0,mat1;
遍历当前数据集中所有的特征、所有的特征取值后,选取使得混乱程度最小的A与a,混乱程度的计算方法即为上述相较于mean的总误差;
返回条件:
1)当前目标变量集合(当前数据集)中标签唯一,那么就不需要进行切分,直接返回;
2)切分后效果提升不大,创建叶节点然后直接返回;
3)对切分后子集的大小进行检测,如果某个子集的大小小于定义的某值,直接返回;
4)如果上述提前终止的条件全都不符合,那么就返回切分特征和特征值

①对数据进行加载

def loadDataSet(file):    dataSet = []    f = open(file)    for line in f.readlines():        cur_line = line.strip().split('\t')        flt_line = map(float,cur_line)        dataMat.append(flt_line)    return dataSet

返回[[],[],[],…,[]]

②将传入的dataSet进行切分(按A、a遍历一遍),返回两个matrix,分别为yi 大于或小于等于定义的value

def binSplit(dataSet,feature,value):    mat0 = dataSet[np.nonzero(dataSet[:,feature] > value)[0],:]    mat1 = dataSet[np.nonzero(dataSet[:,feature] <= value)[0],:]    return mat0,mat1

③检测一下上一步输出的mat0,mat1是否满足提前终止的条件,如果满足,返回;如果不满足,则继续进行下一步操作
计算根据A、a划分后的混乱程度,为mat0与mat1混乱程度的加和,此处直接使用方差*dataSet中数据总量,得到总方差

def chaos(dataSet):    return np.var(dataSet[:,-1]) * np.shape(dataSet)[0]

然后对当前得到的总方差与历史最小方差进行比较,如果当前chaos表现更优,则更新历史chaos、当前feature索引、当前feature取值
遍历后,得到bestIndex,bextValue,再将其带回binSplit中,获得mat0,mat1
返回

def chooseBestSplit(dataSet,leafType=regLeaf,chaos=chaos,ops=(1,4)):    tolS = ops[0];tolN = ops[1]    if len(set(dataSet[:,-1].T.tolist()[0])) == 1:        return None,leafType(dataSet)    m,n = np.shape(dataSet)    S = chaos(dataSet)    beatS = np.inf;bestIndex = 0;bestValue = 0;    for fea_index in range(n-1):        for val in set((dataSet[:,fea_index].T.A.tolist())[0]):            mat0,mat1 = binSplit(dataSet,fea_index,val)            if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN):continue            newS = chaos(mat0) + chaos(mat1)            if newS < beatS:                bestIndex = fea_index                bestValue = val                beatS = newS    if (S - beatS) < tolS:        return None,leafType(dataSet)    mat0,mat1 = binSplit(dataSet,bestIndex,bestValue)    if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN):        return None,leafType(dataSet)    print 'end***'    return bestIndex,bestValue

这儿是不是不能上传代码…机器学习实战那本书上的代码运行有问题,对其做了修改,代码和数据应该在在资源页……