目录
1. 树回归简介
上一节介绍了线性回归模型,但是在实际生活中许多问题都是非线性的,或者分段线性的因此很难建立一个全局的线性模型。为了解决这一问题,可以使用树回归。树回归的基本原理是将问题划分成一个个较小的子问题,如果子问题可以建立线性模型,那么就可以自底向上解决全局的回归问题。
2. 树回归模型
回归树模型和决策树类似,包括特征选择、回归树生成和回归规则
2.1 特征选择
在决策树中,我们使用了信息增益作为特征选择的依据。但是对于回归树来说,由于需要预测的是连续的数值,其经验熵不能很好的表达有用的信息(因为回归标签几乎每个都不同),因此这里使用预测误差作为特征选择的依据。这里采用平方差作为误差的评价,即
其中 为回归树将输入空间划分成 个单元(相当于子树),并且在每个单元上有固定的输出值,即
也就是说,被划到 这个单元里的 ,不论其特征值为什么,其结果都是固定的。每个单元上的预测结果为划分到该单元上的所有样本的平均值。因此
特征选择与划分同决策树类似,遍历所有特征和其所有对应的值使得预测误差最小
2.2 回归树生成
回归树生成同决策树生成一样,采用递归的方式生成树。存储结构也类似
def __init__(self, index=-1, value=None, result=None, right_tree=None, left_tree=None):
self.index = index
self.value = value
self.result = result
self.right_tree = right_tree
self.left_tree = left_tree
回归树生成算法于决策树类似,假设已经获得了切分特征和其对应特征值组 ,那么划分规则如下
两个单元对应的输出值为
决策树生成代码如下:
def createRegressionTree(self, data):
# if there is no feature
if len(data) == 0:
self.tree_node = treeNode(result=self.getMean(data[:, -1]))
return self.tree_node
sample_num, feature_dim = np.shape(data)
best_criteria = None
best_error = np.inf
best_set = None
initial_error = self.getVariance(data)
# get the best split feature and value
for index in range(feature_dim - 1):
uniques = np.unique(data[:, index])
for value in uniques:
left_set, right_set = self.divideData(data, index, value)
if len(left_set) < self.N or len(right_set) < self.N:
continue
new_error = self.getVariance(left_set) + self.getVariance(right_set)
if new_error < best_error:
best_criteria = (index, value)
best_error = new_error
best_set = (left_set, right_set)
if best_set is None:
self.tree_node = treeNode(result=self.getMean(data[:, -1]))
return self.tree_node
# if the descent of error is small enough, return the mean of the data
elif abs(initial_error - best_error) < self.error_threshold:
self.tree_node = treeNode(result=self.getMean(data[:, -1]))
return self.tree_node
# if the split data is small enough, return the mean of the data
elif len(best_set[0]) < self.N or len(best_set[1]) < self.N:
self.tree_node = treeNode(result=self.getMean(data[:, -1]))
return self.tree_node
else:
ltree = self.createRegressionTree(best_set[0])
rtree = self.createRegressionTree(best_set[1])
self.tree_node = treeNode(index=best_criteria[0], value=best_criteria[1], left_tree=ltree, right_tree=rtree)
return self.tree_node
2.3 回归规则
回归树回归规则也和决策树类似,二叉排序树类似,根据待检测样本的指定特征和其特征值与决策树结点存储的特征值进行比较,根据结果将其送入左子树或者右子树,其代码如下:
def classify(self, sample, tree):
if tree.result is not None:
return tree.result
else:
value = sample[tree.index]
if value >= tree.value:
branch = tree.right_tree
else:
branch = tree.left_tree
return self.classify(sample, branch)
3. 总结与分析
回归树和决策树可以组合成分类回归树(CART),我将其拆分为决策树和回归树。因为我觉得虽然它们有很多类似之处但是采用的一些标准有所不同。关于剪枝,分为预剪枝和后剪枝。最后贴一下本文实现的回归树与Sklearn检测性能的比较:
Sklearn 树回归结果
本文实现树回归结果
可以发现效果差不多,但是Sklearn的运行时间要少得多。
本文相关代码和数据集:https://github.com/Ryuk17/MachineLearning
[1] 李航, 统计学习方法
[2] Peter Harrington, Machine Learning IN ACTION