共计 2178 个字符,预计需要花费 6 分钟才能阅读完成。
决策树是机器学习中最直观的算法之一,常用于分类和回归任务,比如客户分群、医疗诊断等场景。它的优势在于模型可解释性强,甚至可以手动推导计算过程。下面我们通过一个完整的案例,从数据准备到模型优化,一步步拆解 CART 决策树的实现过程。

数据准备:鸢尾花数据集简化版
我们使用 sklearn 自带的鸢尾花数据集,但为了简化演示,只保留前两个特征(萼片长度和宽度)以及两个类别(Setosa 和 Versicolor):
from sklearn.datasets import load_iris
import pandas as pd
# 加载并简化数据
iris = load_iris()
df = pd.DataFrame(iris.data[:, :2], columns=['sepal_length', 'sepal_width'])
df['target'] = iris.target
df = df[df['target'].isin([0,1])] # 只保留两类
分裂准则:基尼系数实战计算
CART 决策树默认使用基尼系数衡量节点纯度。假设当前节点有 N 个样本,基尼系数计算公式为:
$$Gini = 1 – \sum_{k=1}^{K}(p_k)^2$$
其中 $p_k$ 是第 k 类样本的比例。我们手动计算第一个分裂点的基尼系数:
- 遍历所有可能的分裂点(每个特征的所有取值)
- 计算分裂后左右子节点的基尼系数加权和
- 选择使加权基尼系数最小的分裂点
# 示例:计算按 sepal_length=5.4 分裂的基尼系数
left_node = df[df['sepal_length'] <= 5.4]
right_node = df[df['sepal_length'] > 5.4]
gini_left = 1 - (len(left_node[left_node['target']==0])/len(left_node))**2 \
- (len(left_node[left_node['target']==1])/len(left_node))**2
gini_right = 1 - (len(right_node[right_node['target']==0])/len(right_node))**2 \
- (len(right_node[right_node['target']==1])/len(right_node))**2
total_gini = (len(left_node)/len(df))*gini_left \
+ (len(right_node)/len(df))*gini_right
递归构建决策树
决策树的生长本质是递归分裂过程,伪代码如下:
def build_tree(node):
if 当前节点样本全属于同一类别:
return 叶节点
计算所有特征的最佳分裂点
if 无法找到有效分裂点:
return 叶节点(多数类)按最佳分裂点划分左右子树
left_node = build_tree(左子集)
right_node = build_tree(右子集)
return 决策节点 (分裂条件, left_node, right_node)
Python 完整实现
使用 sklearn 的完整训练流程:
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn.model_selection import train_test_split
import graphviz
# 数据划分
X = df[['sepal_length', 'sepal_width']]
y = df['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# 模型训练(使用基尼系数)clf = DecisionTreeClassifier(criterion='gini', max_depth=3)
clf.fit(X_train, y_train)
# 评估
print("Test accuracy:", clf.score(X_test, y_test))
# 可视化
dot_data = export_graphviz(clf, out_file=None,
feature_names=X.columns,
class_names=['Setosa','Versicolor'],
filled=True)
graph = graphviz.Source(dot_data)
graph.render('iris_tree') # 保存为 PDF
关键参数调优建议
- 处理连续特征 :决策树自动处理连续值,但要注意特征缩放不影响分裂
- 类别不平衡 :设置 class_weight=’balanced’ 或调整样本权重
- 避免过拟合 :
- 预剪枝:限制 max_depth/min_samples_split/min_impurity_decrease
- 后剪枝:ccp_alpha 参数(代价复杂度剪枝)
可视化解读
生成的决策树图中需要关注:
– 每个节点的分裂条件和基尼系数
– 样本数量分布
– 颜色深浅表示类别纯度
进阶思考
- 随机森林如何通过多棵决策树提升性能?
- 相比逻辑回归,决策树更适合哪些数据类型?
- 当特征维度很高时,如何优化决策树的训练速度?
通过这个小案例,你应该已经掌握了决策树的核心构建逻辑。建议尝试修改参数观察树结构变化,这是理解算法最好的方式。
正文完
