从零实现机器学习算法(十)树回归(Tree Regression)

目录

1. 树回归简介

2. 树回归模型

2.1 特征选择

2.2 回归树生成

2.3 回归规则

3. 总结与分析


1. 树回归简介

上一节介绍了线性回归模型,但是在实际生活中许多问题都是非线性的,或者分段线性的因此很难建立一个全局的线性模型。为了解决这一问题,可以使用树回归。树回归的基本原理是将问题划分成一个个较小的子问题,如果子问题可以建立线性模型,那么就可以自底向上解决全局的回归问题。

2. 树回归模型

回归树模型和决策树类似,包括特征选择、回归树生成和回归规则

2.1 特征选择

在决策树中,我们使用了信息增益作为特征选择的依据。但是对于回归树来说,由于需要预测的是连续的数值,其经验熵不能很好的表达有用的信息(因为回归标签几乎每个都不同),因此这里使用预测误差作为特征选择的依据。这里采用平方差作为误差的评价,即

\sum_{x_{i}\in R_{m}}\left(y_{i}-f\left(x_{i}\right)\right)^{2}

其中 R_{m} 为回归树将输入空间划分成 M 个单元(相当于子树),并且在每个单元上有固定的输出值,即

f\left(x\right)=\sum_{m=1}^{M}c_{m}I\left(x\in R_{m}\right)

也就是说,被划到 R_{m} 这个单元里的 x ,不论其特征值为什么,其结果都是固定的。每个单元上的预测结果为划分到该单元上的所有样本的平均值。因此

c_{m}=\arg \left(y_{i}|x_{i}\in R_{m}\right)

特征选择与划分同决策树类似,遍历所有特征和其所有对应的值使得预测误差最小

\min\limits_{j,s}\left[\min\limits_{c_{1}}\sum_{x_{i}\in R_{1}\left(j,s\right)}\left(y_{i}-c_{1}\right)+\min\limits_{c_{2}}\sum_{x_{i}\in R_{2}\left(j,s\right)}\left(y_{i}-c_{2}\right)\right]

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

回归树生成算法于决策树类似,假设已经获得了切分特征和其对应特征值组 \left(j,s\right) ,那么划分规则如下

R_{1}\left(j,s\right)=\left\{ x|x^{(j)}\leq s\right\}

R_{2}\left(j,s\right)=\left\{ x|x^{(j)}> s\right\}

两个单元对应的输出值为

c_{m}=\frac{1}{N_{m}}\sum_{x_{i}\in R_{m}\left(j,s\right)}y_{i},x\in R_{m} ,m=1,2

决策树生成代码如下:

    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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值