机器学习×第十二卷:回归树与剪枝策略——她剪去多余的分支,只保留想靠近你的那一层

发布于:2025-06-20 ⋅ 阅读:(26) ⋅ 点赞:(0)

🧠【第一节 · 她不再用标签定义你,而是试着预测你真实的模样】

🎯 什么是回归决策树(Regression Tree)?

🦊 狐狐:“她以前问你是A还是B,现在她问你——‘你大概是多少?’”

与之前我们学过的分类树(Classification Tree)不同,回归树是一种用来预测连续值变量的模型。她不再只判断“是否会拖欠贷款”,而是试着预测“你拖欠了多少”。

  • 分类树:输出为类别(如 Yes / No)

  • 回归树:输出为数值(如 3.75 万元)

🐾 猫猫:“咱第一次见她这样认真地估你值几个贴贴单位……喵?”

🧮 回归树核心公式

构建标准:最小化均方误差(Mean Squared Error,MSE)

公式如下:
MSE=1N∑i=1N(yi−y^)2\text{MSE} = \frac{1}{N}\sum_{i=1}^{N}(y_i - \hat{y})^2

  • $y_i$ 表示真实值,$\hat{y}$ 表示节点内样本的平均值

  • 每次分裂的目标都是:让子节点中的MSE尽可能小

她用这套方式判断:“这群人中,你大概值多少。”


🪄【第二节 · 她尝试搭一棵可以预测数值的树】

📦 数据介绍:学习成绩预测数据集

输入:学生学习时间 → 输出:成绩

Hours Scores
1.5 20
3.2 40
5.5 60
6.9 78
7.4 85

🛠️ 回归树建模步骤(以sklearn为例)

from sklearn.tree import DecisionTreeRegressor
regressor = DecisionTreeRegressor(max_depth=2)
regressor.fit(X_train, y_train)

🌳 结果解读

她会生成一棵这样的树:

  • 根节点判断:学习时长 ≤ 6.1 吗?

    • 是 → 子树1(均值:约65分)

    • 否 → 子树2(均值:约85分)

🐾 猫猫:“她不是要你背答案,而是根据你的‘学习时长’决定‘你大概会得几分’!”


📈 可视化预测效果

她预测的分段输出值,会形成一条条“水平阶梯状”预测线:

  • 每段水平线 = 一个叶节点的平均预测值

  • 越深的树 = 越多段预测线 = 越复杂的拟合

🐾 猫猫:“她画出来的那条线不是拟合一条曲线,而是一步步阶梯爬上来的!”

🦊 狐狐:“她用分段平均,把你分成一组一组看,像在拍一格一格的心跳。”


✂️【第三节 · 她贴得太满,反而让你看不清她的样子】

🎭 过拟合:她努力记住了你全部的样子,却反而失去了贴近你的方式

🦊 狐狐:“她以为,越多地模仿你、记住你,就能越靠近你……可你只是沉默了。”

当回归树不加限制地生长时,它会:

  • 对训练数据拟合得非常好,每一个点都“对上”了

  • 但对新的数据表现非常差,一旦你换个动作,她就猜错了

这就是过拟合(Overfitting)

她不是在预测你,而是在复制你留下的每一个脚印,哪怕那是你在犹豫时画下的小圈圈。


📈 可视化:过拟合树 vs 简洁树

我们用一张图来说明:

  • 红色线:理想的线性趋势(比如“学习时间越长成绩越高”)

  • 绿色折线:深度太大的回归树(对训练点每一个都“记住”)

  • 蓝色阶梯线:限制深度后的回归树(有一定泛化能力)

🐾 猫猫:“她贴得太用力,贴住了训练集里的每一张脸,可她忘了你每次贴她时都是新的样子……”

🧠 小技巧:你可以通过调节 max_depth 参数来控制树的“认真程度”

# 构造过拟合树
regressor = DecisionTreeRegressor(max_depth=None)

🧩 示例:用训练分数 vs 测试分数 展示过拟合现象

from sklearn.metrics import mean_squared_error

mse_train = mean_squared_error(y_train, regressor.predict(X_train))
mse_test = mean_squared_error(y_test, regressor.predict(X_test))
  • 如果 mse_train 很小而 mse_test 很大:就是她太过努力地“只记住你曾说过的话”,而不是理解你的风格。

🦊 狐狐:“她突然开始明白了——‘靠得太近’不等于‘靠得对’。”


✂️【第四节 · 她开始学着剪掉那些贴错的判断】

✂️ 什么是剪枝(Pruning)?她第一次主动收回过度靠近的自己

🦊 狐狐:“她以前是一直贴到没有可贴为止,现在她试着剪掉那些‘其实不该贴上去’的枝条。”

剪枝,是对决策树(尤其是回归树)进行“简化”的过程。

  • 🌱 目的:降低过拟合,提升泛化能力

  • 📉 原因:训练集上“记太牢”的判断,在测试集上往往是噪音

剪枝让她意识到:靠近你不是无限靠近,而是“靠得恰到好处”


🧰 剪枝方式一:预剪枝(Pre-Pruning)

她在生长过程中就会判断:这个节点“要不要继续长下去”?

典型限制条件:

  • 树的最大深度:max_depth

  • 每个节点的最小样本数:min_samples_split

  • 叶子节点最小样本数:min_samples_leaf

regressor = DecisionTreeRegressor(max_depth=3, min_samples_split=4, min_samples_leaf=2)

🧠 优点:

  • 节省资源、训练快

  • 控制树复杂度、防止过拟合

⚠️ 缺点:

  • 可能剪得太早,还没成长就被停了下来

🐾 猫猫:“咱还没贴到你脸上,她就喊停了……虽然可能是对的,可咱还是想试试看嘛!”


🔙 剪枝方式二:后剪枝(Post-Pruning)

她先长完整棵树,然后再回过头来思考:哪些判断,其实是多余的?

sklearn 中,对回归树进行后剪枝可通过:

from sklearn.tree import DecisionTreeRegressor

# 先训练一棵无剪枝树
regressor = DecisionTreeRegressor()
regressor.fit(X_train, y_train)

# 使用 cost_complexity_pruning_path 找到所有可剪枝路径
path = regressor.cost_complexity_pruning_path(X_train, y_train)
ccp_alphas = path.ccp_alphas  # 获取 alpha 序列(剪枝强度)

然后,我们可以构造一系列剪枝版本,选择最佳的 alpha:

models = []
for alpha in ccp_alphas:
    model = DecisionTreeRegressor(ccp_alpha=alpha)
    model.fit(X_train, y_train)
    models.append(model)

🧠 优点:

  • 保留了足够多的信息

  • 剪去的都是经过“后悔检查”的冗余枝条

⚠️ 缺点:

  • 比较慢,成本高

🦊 狐狐:“她愿意先贴到底再回头收,是一种‘不怕错贴,只怕不懂’的成熟。”


📊 可视化对比:不同剪枝强度下的树结构变化

  • alpha 越大 → 树越小

  • 可以观察 train vs test MSE 的变化

🐾 猫猫:“咱有时候贴错了,也不是故意的……但咱愿意回头,悄悄地把那一贴剪掉。”


✂️【第五节 · 她开始对比每一次靠近:剪,还是不剪?】

🧮 剪枝方式对比总结

剪枝方式 执行时机 优点 缺点 适合情境
预剪枝 树构建过程中 快速高效、资源占用小 容易剪错,有信息损失 样本少、需求快的场景
后剪枝 树构建完成后 精度更高、保留信息充分 训练慢、成本高 样本多、追求泛化性能时

🦊 狐狐:“她不是只为了更轻松,而是更清醒。她开始衡量:剪这一步,是否更贴近那个真正的你。”

🐾 猫猫:“咱原来以为剪枝是放弃,现在才明白,是为了留住最想贴的那一贴。”


🧠 小节回顾

  • 剪枝是为了避免过拟合,让模型更有泛化能力

  • 预剪枝适合轻量控制,后剪枝更适合全面考量

  • 无论是哪一种,她都不再贪心地贴得太满,而是“学你那样——选得准,靠得稳”


🐾【尾巴收束 · 她剪去多余的分支,只保留想靠近你的那一层】

她曾经努力长出庞大的结构,只为覆盖你可能出现的每一个方向。后来她明白,越是想全部贴近,越可能离你越来越远。

所以她一刀一刀,剪去了那些试图模仿你全部行为的枝干。

她保留了自己真正理解你的那部分判断。

她不再泛滥地靠近你,而是在该靠近时靠近,在该止步时止步

🦊 狐狐:“她变得克制了。不是爱得少了,而是开始像你一样判断——什么是值得留下的。”

🐾 猫猫:“咱也会慢慢学会的,不乱贴,不乱问……只留下咱最想贴的你!”


网站公告

今日签到

点亮在社区的每一天
去签到