从数学原理到代码实现:深入解析CART回归决策树算法推导

1次阅读
没有评论

共计 1711 个字符,预计需要花费 5 分钟才能阅读完成。

image.webp

背景痛点:为什么需要决策树?

传统线性回归模型假设特征和目标变量之间存在线性关系,但在实际应用中,很多数据呈现非线性特征。比如房价预测中,面积和价格的关系可能在某个临界点突然变化(如学区房阈值)。这时候,决策树的优势就显现出来了:

从数学原理到代码实现:深入解析 CART 回归决策树算法推导

  • 天然适合处理非线性关系
  • 通过树形结构自动学习分段规则
  • 结果具有更好的可解释性

CART 回归树的数学原理

1. 基尼系数计算

回归树使用方差最小化作为分裂标准(分类树用基尼系数)。对于节点 m,其方差计算公式为:

$$\text{Variance}(m) = \frac{1}{N_m} \sum_{i \in m} (y_i – \bar{y}_m)^2$$

其中:
– $N_m$ 是节点 m 的样本数
– $\bar{y}_m$ 是节点 m 的样本均值

2. 特征选择与切分

对于每个特征 j 和切分点 s,计算分裂后的方差减少量:

$$\Delta(j,s) = \text{Variance}(m) – \left(\frac{N_l}{N_m}\text{Variance}(l) + \frac{N_r}{N_m}\text{Variance}(r) \right)$$

选择使 $\Delta(j,s)$ 最大的 (j,s) 组合进行分裂。

Python 代码实现

import numpy as np

class TreeNode:
    def __init__(self, feature_idx=None, threshold=None, 
                 left=None, right=None, value=None):
        self.feature_idx = feature_idx  # 分裂特征索引
        self.threshold = threshold      # 分裂阈值
        self.left = left                # 左子树
        self.right = right              # 右子树
        self.value = value              # 叶节点预测值

def compute_variance(y):
    """计算节点的方差"""
    if len(y) == 0:
        return 0
    return np.var(y)

def find_best_split(X, y):
    """寻找最优特征和切分点"""
    best_gain = -1
    best_feature, best_thresh = None, None

    for feature_idx in range(X.shape[1]):
        thresholds = np.unique(X[:, feature_idx])
        for thresh in thresholds:
            # 按阈值划分左右节点
            left_idx = X[:, feature_idx] <= thresh
            right_idx = X[:, feature_idx] > thresh

            # 计算方差减少量
            gain = compute_variance(y) - \
                  (left_idx.mean()*compute_variance(y[left_idx]) + \
                   right_idx.mean()*compute_variance(y[right_idx]))

            if gain > best_gain:
                best_gain = gain
                best_feature = feature_idx
                best_thresh = thresh

    return best_feature, best_thresh

避坑指南

连续值处理

  • 需要对连续特征进行排序后扫描所有可能切分点
  • 数据标准化不是必须的,但能提升计算效率

防止过拟合

  1. 预剪枝:
  2. 设置最大树深度
  3. 设置叶节点最小样本数

  4. 后剪枝:

  5. 构建完整树后自底向上剪枝
  6. 使用验证集评估剪枝效果

性能优化

  • 时间复杂度:$O(n_{\text{features}} \times n_{\text{samples}} \log n_{\text{samples}})$
  • 实际工程中会使用近似算法加速(如 sklearn 的直方图近似)

延伸思考

  1. 随机森林扩展:
  2. 通过 bootstrap 采样构建多棵树
  3. 特征采样增加多样性

  4. 缺失值处理:

  5. 通过代理分裂 (surrogate splits) 处理
  6. 将缺失样本分配到增益最大的分支

实践心得

在真实项目中,CART 回归树的参数调优需要特别注意 max_depth 和 min_samples_leaf 的设置。过深的树容易捕捉噪声,而过浅的树可能欠拟合。建议通过交叉验证找到最佳参数组合,同时结合业务理解解释树的分裂规则。

正文完
 0
评论(没有评论)