CART回归树
如果样本的标签和样本的特征存在非线性关系时,则普通的线性回归、岭回归和Lasso回归都不再使用。
局部加权回归也可以对非线性数据进行较好的拟合,但是它是非参数模型,每次预测都要重新训练模型参数,计算量太大,耗费时间。
CART树回归算法属于一种局部的回归算法,通过将全局的数据集划分成多份容易建模的数据集,这样在每个个数据集上进行局部的回归建模。
CART回归树用平方误差最小化准则,进行特征选择,生成二叉树。
重点:
一个回归树对应着输入空间(即特征空间)的一个划分以及在划分的单元上的输出值。
1) 如何划分?划分标准时什么?
2)各个划分单元上的输出值怎么确定?
如果回答了以上2个问题,那么回归树模型就确定了。
假设已将输入空间划分为M个单元
,并且在每个单元上都有一个固定的输出值
,于是回归树模型可表示为:
当输入空间的划分确定时,可以用平方误差
来表示回归树关于训练数据的预测误差。
用平方误差最小准则求解每个单元上的最优输出值,易知单元
即
这样就回答了第2个问题,剩下第一个问题 了,那么如何划分呢?
接下来的问题是确定如何划分数据集:
我们采用启发式的方法,选择第j个变量 和它的取值s,作为切分变量和切分点
接下来要回答的是:如何选择最好的切分向量和切分点?
这样考虑:这个切分向量和切分点可以将数据集分成2个区域
按平方误差来计算着两个区域上的误差
最佳的切分向量和切分点对(j,s)是满足以下条件的(j,s)对:
对于固定的切分变量j,可以找到最优的切分点s
和
遍历所有的切分变量j和切分点s,构成一个(j,s)对,选择使上述误差最小的js对对数据集进行划分,分成2个区域R1 和 R2,接着对每个区域重复上述划分过程,直到满足停止条件为止。这样就生成了一颗回归树。
最下二乘回归树生成算法:
输入:训练数据集D
输出:回归树f(x)
在训练数据集所在的输入空间中,递归的将每个区域划分成两个区域并决定每个区域上的输出值,构建二叉树。
1)选择最优切分变量J 与切分点S,求解
遍历变量j,对固定的切分变量j,扫描切分点s,选择使上式达到最小值的对(j,s)
2)用选定的对(j,s)划分区域并决定相应的输出值:
和
/
--------m = 1.2
3)继续对两个子区域调用步骤1)2),直到满足停止条件。
4将输入空间划分为M个区域
,生成决策树
还需要解决一下几个问题:
1)如何计算区域上的平方误差,下面给出python代码:
import numpy as np
def square_error(dataset):
data = np.mat(dataset)
return np.var(data[:,-1]) * np.shape(data)[0]
- 左右子树的划分
根据特征fea中的值value,将数据集data划分成左右子树
def split_tree(data,fea,value):
set_1 =[]
set_2=[]
for x in data:
if x[fea] >= value:
set_1.append(x)
else:
set_2.append(x)
return (set_1,set_2)
- CART回归树的构建:
class node :
def __init__(self,feat=-1,value=None,result=None,right =None,left=None):
self.feat = feat # 用于切分数据集的属性的列索引值
self.value = value#设置划分的值
self.result = result#存储叶子结点的值
self.right =right
self.left = left
def bulid_Tree(data,min_sample,min_error):
# 构建决策树,返回该决策树的根节点
if len(data) <= min_sample:
return node(results = leaf(data))
#初始化
best_err=square_error(data)
bestCriteria = None #存储最佳切分属性和切分点
bestSets=None# 存储切分后的2个数据集
#开始构建CART回归树
feature_num = len(data[0])-1
for fea in range(0,feature_num):
feature_values={}
for sample in data:
feature_values[sample[fea]]=1
for value in feature_values.keys():
(set_1,set_2)=split_Tree(data,fea,value)
if len(set_1)< 2 or len(set_2)<2:
continue
now_err = square_error(set_1)+square_error(set_2)
if now_err < best_err and len(set_1) > 0 and len(set_2)>0:
best_err = now_err
bestCriteria = (fea,value)
bestSets = (set_1,set_2)
# 判断划分是否结束
if best_err > min_err:
right = bulid_Tree(bestSets[0],min_sample,min_err)
left = bulid_Tree(bestSets[1],min_sample,min_err)
return node(fea=bestCriteria[0],value = bestCriteria[1],right = right,left=left]
else:
return node(results=leaf(data))
# 计算该区域中所有样本的标签的均值
def leaf(data):
data = np.mat(datSet)
return np.mean(data[:,-1]