深入解析CART决策树原理:从数学基础到Python实现

1次阅读
没有评论

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

image.webp

1. 决策树基础概念

决策树算法家族中,CART(Classification and Regression Trees)是最经典的实现之一。与 ID3 和 C4.5 不同,CART 有两大特点:

深入解析 CART 决策树原理:从数学基础到 Python 实现

  • 使用 基尼系数(Gini Index)作为分裂标准(分类任务)
  • 能同时处理分类和回归任务(通过方差最小化)

1.1 基尼系数 vs 信息熵

基尼系数和熵都是衡量数据不纯度的指标,但计算方式不同:

# 基尼系数计算公式
gini = 1 - sum(p_i^2 for p_i in class_probabilities)

# 信息熵计算公式  
entropy = -sum(p_i * log2(p_i) for p_i in class_probabilities)

实际应用中,基尼系数计算更快(无需对数运算),而熵对不平衡数据更敏感。

2. CART 分裂的数学原理

2.1 特征选择过程

对于每个特征,CART 会:

  1. 计算该特征所有可能划分点的基尼指数
  2. 选择使基尼指数最小的划分点

基尼指数计算公式:

Gini_index = p_left * Gini_left + p_right * Gini_right

2.2 计算示例

假设我们有以下数据(二分类问题):

年龄 收入 是否购买
青年 高 否
青年 低 否
中年 高 是
老年 中 是

以 ” 年龄 ” 特征为例:

  1. 计算整体基尼系数:1 – (0.5² + 0.5²) = 0.5
  2. 尝试划分点 ” 青年 ”:
  3. 左节点基尼:1 – (0² + 1²) = 0
  4. 右节点基尼:1 – (1² + 0²) = 0
  5. 基尼指数:0.50 + 0.50 = 0

这是完美的划分,因此会选择这个分裂点。

3. Python 实现完整 CART 树

3.1 节点类定义

class DecisionNode:
    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              # 叶节点预测值

3.2 核心递归分裂函数

def fit(self, X, y):
    # 终止条件 1:所有样本属于同一类
    if len(set(y)) == 1:
        return DecisionNode(value=y[0])

    # 终止条件 2:没有更多特征可用
    if self.max_depth is not None and self.current_depth >= self.max_depth:
        return DecisionNode(value=self._most_common_label(y))

    # 寻找最佳分裂
    best_gini = float('inf')
    best_feature, best_thresh = None, None

    for feature_idx in range(X.shape[1]):
        # 对每个特征尝试所有可能的分裂点
        thresholds = np.unique(X[:, feature_idx])
        for threshold in thresholds:
            left_idx = X[:, feature_idx] <= threshold
            gini = self._calculate_gini(y[left_idx], y[~left_idx])

            if gini < best_gini:
                best_gini = gini
                best_feature = feature_idx
                best_thresh = threshold

    # 递归构建子树
    left_idx = X[:, best_feature] <= best_thresh
    left = self.fit(X[left_idx], y[left_idx])
    right = self.fit(X[~left_idx], y[~left_idx])

    return DecisionNode(best_feature, best_thresh, left, right)

4. sklearn 的优化实现

sklearn 中的 DecisionTreeClassifier 做了多项优化:

  1. 预排序算法:对连续特征预排序,加速最佳分裂点搜索
  2. 并行计算 :通过n_jobs 参数支持特征级别的并行
  3. 内存优化 :使用presort 参数控制是否预排序(大数据集建议关闭)

5. 生产环境注意事项

5.1 过拟合问题

  • 设置 max_depth 限制树深度
  • 使用 min_samples_split 控制分裂最小样本数
  • 通过 ccp_alpha 参数进行代价复杂度剪枝

5.2 类别不平衡

  • 设置class_weight='balanced'
  • 使用 SMOTE 过采样少数类

5.3 高基数特征

  • 对类别型特征进行目标编码(Target Encoding)
  • 考虑使用均值编码或 WOE 编码

6. 思考与扩展

  1. 连续值处理改进:可以考虑使用分箱(binning)或局部回归
  2. 随机森林的作用:通过多棵树的投票机制,减少单棵树的方差

通过本文的实现,你应该已经掌握了 CART 决策树的核心原理。建议尝试在真实数据集(如 sklearn 的乳腺癌数据集)上应用这些知识,观察不同参数对模型性能的影响。

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