深入解析CART决策树的计算步骤:从数学原理到Python实现

1次阅读
没有评论

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

image.webp

基尼系数与熵的数学对比

决策树的核心是选择最优分裂特征,CART 算法使用基尼系数(Gini Index),而 ID3/C4.5 使用信息熵(Entropy)。两者都衡量数据不纯度,但有显著差异:

深入解析 CART 决策树的计算步骤:从数学原理到 Python 实现

  • 基尼系数:计算概率平方和的补数,公式为 $Gini = 1 – \sum_{k=1}^K p_k^2$
  • 计算速度更快(无对数运算)
  • 对类别分布变化更敏感

  • 信息熵:基于信息论的概念,公式为 $H = -\sum_{k=1}^K p_k \log_2 p_k$

  • 对不平衡数据更鲁棒
  • 倾向于产生更平衡的树

实际应用中,两者结果通常差异不大,但基尼系数计算效率更高,这是 CART 算法选择它的主要原因。

特征选择与分裂阈值计算

  1. 单特征基尼计算
    对于特征 A 的可能取值 $a_i$,计算分裂后的加权基尼系数:
    $$Gini_{split} = \frac{|D_1|}{|D|}Gini(D_1) + \frac{|D_2|}{|D|}Gini(D_2)$$

  2. 连续特征处理

  3. 排序特征值
  4. 取相邻值中点作为候选切分点
  5. 选择使基尼系数降低最多的切分点

  6. 最优特征选择
    遍历所有特征和切分点,选择使 $Gini_{split}$ 最小的组合

Python 实现核心代码

import numpy as np
from sklearn.datasets import load_iris

class Node:
    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 gini(y):
    """计算基尼系数"""
    classes = np.unique(y)
    gini = 1.0
    for cls in classes:
        p = len(y[y == cls]) / len(y)
        gini -= p**2
    return gini

def find_best_split(X, 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 thresh in thresholds:
            left_idx = X[:, feature_idx] <= thresh
            left_gini = gini(y[left_idx])
            right_gini = gini(y[~left_idx])
            weighted_gini = (left_gini * len(y[left_idx]) + right_gini * len(y[~left_idx])) / len(y)

            if weighted_gini < best_gini:
                best_gini = weighted_gini
                best_feature = feature_idx
                best_thresh = thresh

    return best_feature, best_thresh

性能优化实践

剪枝策略

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

  5. 后剪枝

  6. 通过验证集评估剪枝收益
  7. 递归地将非叶节点替换为叶节点,如果验证精度不下降

连续特征优化

  • 使用分箱法 (binning) 减少候选切分点
  • 采用近似算法选择百分位点

常见问题避坑指南

  1. 参数配置误区
  2. max_depth过大导致过拟合
  3. min_samples_split过小产生噪声敏感
  4. 忽略 class_weight 处理不平衡数据

  5. 过拟合识别

  6. 训练准确率高但测试准确率低
  7. 树结构出现非常深的分支
  8. 叶节点样本数差异巨大

思考进阶方向

  1. 如何通过 bootstrap 采样和特征抽样,将 CART 扩展为随机森林?
  2. 当遇到类别不平衡数据时,除了调整 class_weight,还有哪些改进方案?
  3. CART 与 GBDT 在模型构建方式上有何本质区别?

通过手动实现 CART 算法,我们能更深入理解决策树的工作机制,为后续学习集成算法打下坚实基础。建议读者尝试在更大数据集上测试代码,并观察不同参数对模型性能的影响。

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