共计 1666 个字符,预计需要花费 5 分钟才能阅读完成。
一、为什么选择 CART 算法?
刚入门机器学习时,我发现决策树虽然直观,但面对这些问题总是头疼:

- 特征太多不知道该选哪个作为分裂节点
- 训练集表现很好但测试集准确率暴跌(典型的过拟合)
- 遇到连续型特征就手足无措
后来发现 CART 算法完美解决这些痛点——它用二叉树结构统一处理分类和回归任务,通过基尼系数自动选择最佳分裂特征,还能通过剪枝控制过拟合。
二、CART 与其他决策树算法的区别
- 与 ID3 对比
- ID3 只能用信息增益,且只能处理离散特征
-
CART 改用基尼系数,计算效率更高(不用算 log)
-
与 C4.5 对比
- C4.5 虽然支持连续值,但生成的是多叉树
- CART 强制二叉树结构,模型更简洁
关键优势:
# CART 处理连续特征的示例
age = [12, 15, 18, 22, 30]
# 会自动尝试所有可能的分割点:# age<=12.5、age<=16.5...
三、手把手实现 CART 核心逻辑
3.1 基尼系数计算
公式看起来复杂其实很简单:
$$Gini(p) = 1 – \sum_{k=1}^K p_k^2$$
实际计算时:
- 统计当前节点各类别的占比
- 用 1 减去各占比平方和
Python 实现:
def gini_impurity(y):
_, counts = np.unique(y, return_counts=True)
proba = counts / len(y)
return 1 - np.sum(proba ** 2)
3.2 递归分裂过程
关键步骤:
- 遍历所有特征的所有可能分割点
- 选择使基尼系数下降最多的分裂方案
- 递归处理左右子树直到满足停止条件
终止条件建议设置:
- 节点样本数 <min_samples_leaf
- 深度达到 max_depth
- 基尼下降小于 min_impurity_decrease
四、sklearn 实战调优技巧
4.1 重要参数解析
from sklearn.tree import DecisionTreeClassifier
# 关键参数设置示例
tree = DecisionTreeClassifier(
criterion='gini', # 一定要选这个!max_depth=5, # 控制树深防过拟合
min_samples_leaf=10, # 每个叶节点最少样本
class_weight='balanced' # 处理类别不平衡
)
4.2 交叉验证选择最优深度
from sklearn.model_selection import GridSearchCV
params = {'max_depth': range(3, 8)}
grid = GridSearchCV(tree, params, cv=5)
grid.fit(X_train, y_train)
print(f'最佳深度:{grid.best_params_}')
五、新手常见踩坑点
5.1 类别不平衡陷阱
错误做法:
- 直接使用原始数据训练
正确方案:
# 方法 1:设置 class_weight
tree = DecisionTreeClassifier(class_weight='balanced')
# 方法 2:过采样少数类
from imblearn.over_sampling import SMOTE
X_res, y_res = SMOTE().fit_resample(X, y)
5.2 特征重要性误读
注意:
- 重要性高的特征不一定因果关系强
- 重要性受特征间相关性影响
- 用 permutation_importance 更可靠
六、进阶方向建议
- 尝试回归任务
- 改用 DecisionTreeRegressor
-
分裂标准变为 MSE/MAE
-
升级到随机森林
- CART 是随机森林的基学习器
- 通过 ensemble 降低方差
# 随机森林示例
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(
n_estimators=100,
max_features='sqrt' # 特征采样
)
写在最后
通过这个实战项目,我深刻体会到:
- CART 的二叉树结构让模型解释性极佳
- 合理剪枝比追求训练集高分更重要
- sklearn 的参数看似简单实则影响巨大
建议大家在泰坦尼克数据集上动手实现一遍,遇到问题欢迎在评论区交流~
正文完
