决策树实战:从零解析CART算法构造流程与实现细节

1次阅读
没有评论

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

image.webp

1. 初识 CART 算法

CART(Classification and Regression Trees)是决策树家族中最常用的算法之一。与 ID3 和 C4.5 不同,CART 算法可以同时处理分类和回归问题,这使其在实际应用中非常灵活。

决策树实战:从零解析 CART 算法构造流程与实现细节

1.1 分类树 vs 回归树

  • 分类树 :使用基尼系数(Gini Index)作为分裂标准
  • 基尼系数公式:$Gini(D) = 1 – \sum_{k=1}^K (p_k)^2$
  • 其中 $p_k$ 是样本属于第 k 类的概率

  • 回归树 :使用平方误差最小化作为分裂标准

  • 目标是最小化:$\sum_{i \in R_1}(y_i – c_1)^2 + \sum_{i \in R_2}(y_i – c_2)^2$
  • 其中 $c_1$ 和 $c_2$ 是两个子区域的输出均值

2. CART 算法核心流程

2.1 特征选择

  1. 对于分类问题 :
  2. 计算每个特征的基尼指数
  3. 选择使基尼指数减少最多的特征

  4. 对于回归问题 :

  5. 遍历所有可能的切分点
  6. 选择使平方误差最小的切分

2.2 分裂点确定

  • 连续值处理 :
  • 对特征值排序
  • 取相邻值的中点作为候选切分点

  • 离散值处理 :

  • 对于 m 个取值,考虑 $2^{m-1}-1$ 种划分方式
  • 实践中常使用二分法简化计算

2.3 停止条件

  • 节点中的样本数少于预定阈值
  • 所有特征的分裂增益小于预定阈值
  • 树达到最大深度

3. Python 实现详解

import numpy as np
from sklearn.datasets import load_iris

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

class CART:
    """CART 决策树实现"""
    def __init__(self, max_depth=None, min_samples_split=2):
        self.max_depth = max_depth
        self.min_samples_split = min_samples_split

    def fit(self, X, y):
        self.n_classes = len(np.unique(y))
        self.n_features = X.shape[1]
        self.tree = self._grow_tree(X, y)

    def _gini(self, y):
        """计算基尼系数"""
        m = y.size
        return 1.0 - sum((np.sum(y == c) / m) ** 2 for c in range(self.n_classes))

    def _best_split(self, X, y):
        """寻找最佳分裂特征和阈值"""
        # 实现细节省略...

    def _grow_tree(self, X, y, depth=0):
        """递归构建决策树"""
        # 停止条件检查
        if (self.max_depth is not None and depth >= self.max_depth) or \
           len(y) < self.min_samples_split or len(np.unique(y)) == 1:
            return TreeNode(value=self._leaf_value(y))

        # 寻找最佳分裂
        idx, thr = self._best_split(X, y)

        # 递归构建子树
        left_idx = X[:, idx] <= thr
        right_idx = X[:, idx] > thr
        left = self._grow_tree(X[left_idx], y[left_idx], depth+1)
        right = self._grow_tree(X[right_idx], y[right_idx], depth+1)

        return TreeNode(feature_idx=idx, threshold=thr, left=left, right=right)

4. 工程实践技巧

4.1 连续值离散化

  • 使用等频或等宽分桶
  • 考虑使用信息增益最大化确定分界点

4.2 过拟合预防

  • 预剪枝 :
  • 限制树的最大深度
  • 设置节点最小样本数
  • 设置分裂最小增益

  • 后剪枝 :

  • 代价复杂度剪枝(CCP)
  • 使用验证集评估剪枝效果

4.3 类别不平衡处理

  • 为不同类别设置样本权重
  • 使用分层采样
  • 调整决策阈值

5. 性能优化建议

  1. 使用 numpy 向量化操作代替循环
  2. 对连续特征先排序,减少重复计算
  3. 对大型数据集使用近似算法
  4. 并行化特征选择过程

6. 延伸思考

  1. 如何修改代码使其同时支持分类和回归任务?
  2. 当特征维度很高时,如何加速特征选择过程?
  3. 除了基尼系数,还可以使用哪些指标作为分裂标准?

7. 总结

本文详细介绍了 CART 算法的实现原理和工程实践技巧。通过从零实现一个简单的决策树,我们深入理解了特征选择、节点分裂等核心概念。在实际应用中,还需要考虑数据预处理、模型调参等更多因素。希望这篇教程能帮助你更好地理解和应用决策树算法。

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