共计 1918 个字符,预计需要花费 5 分钟才能阅读完成。
为什么需要决策树?
传统线性回归在遇到非线性数据时常常力不从心。比如房价预测中,当存在“学区房价格突变”这类阶梯状分布时,线性模型会强行用一条直线拟合,导致预测偏差较大。此时决策树的优势就显现出来了:

- 能自动捕捉数据中的 if-then 规则(如“如果面积 >100㎡且位于学区,则价格跳涨”)
- 不需要人工构造多项式特征
- 输出结果可解释性强,适合业务方理解
算法核心原理
1. 分类树 vs 回归树
虽然都叫决策树,但两者目标不同:
- 分类树:预测离散类别(如判断邮件是否是垃圾邮件)
- 回归树:预测连续数值(如房价具体金额)
关键区别在于分裂准则:
- 分类树常用基尼系数或信息增益
- 回归树使用均方误差(MSE)
2. MSE 分裂准则推导
回归树每次分裂的目标是最小化左右子节点的 MSE 之和:
MSE = Σ(y_i - y_mean)^2 / n
具体分裂步骤:
- 遍历所有特征的所有可能分割点
- 计算每个分割点产生的左右子节点 MSE 总和
- 选择使 MSE 总和最小的分割方案
3. 特征划分可视化
假设用房屋面积预测价格,分裂过程类似:
graph TD
A[全部样本] -->| 面积≤80㎡| B[均价 1.2 万]
A -->| 面积 >80㎡| C[均价 2.3 万]
C -->| 面积≤120㎡| D[均价 2.1 万]
C -->| 面积 >120㎡| E[均价 3.5 万]
代码实战(Python+sklearn)
数据准备
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt
# 生成演示数据
np.random.seed(42)
X = np.sort(5 * np.random.rand(100, 1), axis=0)
y = np.sin(X).ravel() + np.random.normal(0, 0.1, X.shape[0])
模型训练
# 关键参数说明:# max_depth - 控制树的最大深度,防止过拟合
# min_samples_split - 节点最少样本数
reg = DecisionTreeRegressor(max_depth=3, min_samples_split=5)
reg.fit(X, y)
# 预测演示
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_pred = reg.predict(X_test)
结果可视化
plt.figure()
plt.scatter(X, y, s=20, edgecolor="black", label="数据")
plt.plot(X_test, y_pred, color="red", label="预测", linewidth=2)
plt.xlabel("房屋面积")
plt.ylabel("价格")
plt.legend()
plt.show()
生产环境优化建议
解决过拟合
- 预剪枝 :通过参数控制生长
DecisionTreeRegressor( max_depth=5, # 树的最大深度 min_samples_leaf=10, # 叶节点最少样本数 min_impurity_decrease=0.01 # 分裂最小增益 ) - 后剪枝 :训练完成后再修剪(sklearn 未直接支持,需自定义)
关键参数调优
| 参数名 | 作用 | 推荐取值 |
|---|---|---|
| max_depth | 树的最大深度 | 3-10 |
| min_samples_split | 节点分裂最小样本数 | 2-20 |
| min_samples_leaf | 叶节点最小样本数 | 1-10 |
| max_features | 考虑的最大特征数 | ‘auto’ 或 sqrt(n_features) |
性能与扩展
时间复杂度分析
- 训练:O(n_features * n_samples * log(n_samples))
- 预测:O(tree_depth)
与随机森林对比
| 指标 | 单棵决策树 | 随机森林 |
|---|---|---|
| 预测精度 | 较低 | 较高 |
| 训练速度 | 快 | 慢 |
| 可解释性 | 强 | 弱 |
延伸实验
- 尝试将分裂准则改为 MAE(需自定义 criterion)
- 对比 max_depth= 3 和 max_depth=10 时的过拟合现象
- 用 graphviz 可视化决策树结构(需安装 pydotplus)
from sklearn.tree import export_graphviz
import pydotplus
dot_data = export_graphviz(
reg,
feature_names=['area'],
filled=True
)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_png('tree.png')
决策树就像数据分析界的瑞士军刀,虽然简单但非常实用。刚开始建议先保持默认参数观察效果,再逐步调整。记住:模型越复杂不代表效果越好,有时候限制树的深度反而能获得更稳健的预测结果。
正文完
