共计 2046 个字符,预计需要花费 6 分钟才能阅读完成。
1. 初识 CART 算法
CART(Classification and Regression Trees)是决策树家族中最常用的算法之一。与 ID3 和 C4.5 不同,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 特征选择
- 对于分类问题 :
- 计算每个特征的基尼指数
-
选择使基尼指数减少最多的特征
-
对于回归问题 :
- 遍历所有可能的切分点
- 选择使平方误差最小的切分
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. 性能优化建议
- 使用 numpy 向量化操作代替循环
- 对连续特征先排序,减少重复计算
- 对大型数据集使用近似算法
- 并行化特征选择过程
6. 延伸思考
- 如何修改代码使其同时支持分类和回归任务?
- 当特征维度很高时,如何加速特征选择过程?
- 除了基尼系数,还可以使用哪些指标作为分裂标准?
7. 总结
本文详细介绍了 CART 算法的实现原理和工程实践技巧。通过从零实现一个简单的决策树,我们深入理解了特征选择、节点分裂等核心概念。在实际应用中,还需要考虑数据预处理、模型调参等更多因素。希望这篇教程能帮助你更好地理解和应用决策树算法。
正文完
