清晨的水果摊,张阿姨面对一筐刚到货的橙子。顾客总问“这筐甜不甜?”她不可能每个都切开尝一口,但她有一把分拣尺。第一把尺问:直径超过7厘米吗?橙子分成两堆。第二把尺问:皮是光滑的深橙色吗?每堆再分成两堆。她不断重复,直到每个小堆里的橙子看起来甜度都差不多。最后,她在每只筐上贴一个标签——这堆橙子平均甜度9分。以后有橙子进店,按同样的问题一路问下去,落进哪只筐,就按哪只筐的标签报价。 这就是回归树的核心:用一连串“是/否”的切分问题,把数据不断分成越来越“齐整”的小块,每块用一个平均值当预测结果。它不依赖复杂公式,几条规则走天下,把“预测连续值”这件事拆解成“在哪里切一刀、每块报什么数”两个简单问题。直观、可解释、能捕捉非线性关系——这正是它在房价、销量预测中被广泛使用的原因。

岗位关联

学完回归树,你就能独立完成房价、销量这类连续值预测任务,还能打下理解随机森林、梯度提升树的地基——这是算法工程师面试和实战都绕不开的核心技能。

目录
  1. 可视化演示
  2. 树状切分原理
  3. 特征阈值选择
  4. 均方误差准则
  5. 叶节点均值预测
  6. 过拟合与剪枝
  7. 回归树特点
  8. 应用与扩展
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

动态演示用树状切分做回归的回归树入门的核心机制,通过概览/流程/对比/趋势四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

用树状切分做回归的回归树入门:一回归树 一、回归树基本原理与分类树的区 二、分裂准则:平方误差最小化 核心机制可视化 用树状切分做回归的回归树入门整体架构与关键组件

树状切分原理

张阿姨分橙子的第一步,是先定一个“是不是”的问题:直径超过7厘米吗?超过的进左筐,没超过的进右筐。然后,她在每个筐里再问下一个问题,比如“皮光滑吗”“颜色深吗”。每问一次,筐就被拆成两个更小的筐,直到她满意为止。这一连串“问问题—分堆—再问问题”的流程,就是树形结构最朴素的形态:根节点是第一个问题,每个内部节点是后续的是非题,最终停在哪只筐,哪只筐就是叶子。

在机器学习里,这个分橙子的动作叫递归二分。当预测目标是连续值(甜度、房价、销量)时,这样的决策树就叫回归树,它是 CART(分类回归树)家族里负责回归的那位成员。一棵树从根节点出发,每个内部节点都提出一个“是/否”问题——某个特征是否小于某个阈值;回答“是”走左分支,“否”走右分支。对每个子节点继续提问,直到满足停止条件(比如深度封顶、样本太少),最终到达的节点就是叶子。

一棵训练好的回归树,把整个输入空间切成了 M 个互不重叠的矩形区域。任何新样本都恰好落入其中一个区域,被那片区域内部的平均值接管。

这与张阿姨的筐如出一辙——每个橙子最终只能落进一个筐,不可能同时躺在两只筐里。树把特征空间像切西瓜一样切成小块,每块内部用一个数代表。

X=R1∪R2∪⋯∪RM,Rm∩Rm′=∅  (m≠m′)\displaystyle \mathcal{X} = R_1 \cup R_2 \cup \cdots \cup R_M, \quad R_m \cap R_{m'} = \varnothing \;(m \neq m')
这个式子是说:所有可能的输入(全部橙子的特征组合)被完完整整地划分成了 M 块,任何两块都不重叠,任何橙子都只属于其中一块。
  1. 输入空间$\mathcal{X}$ 表示所有可能的输入(例如面积、房龄这些特征的取值组合),整个空间必须被分完,一个角落都不留。
    X\mathcal{X}
  2. 划分区域每个 $R_m$ 是树上一片叶子对应的特征区域,所有叶子的区域并起来正好等于整个输入空间——“并集”符号 $\cup$ 就是张阿姨把所有筐倒在一起还原整筐橙子的过程。
    R1∪R2∪⋯∪RMR_1 \cup R_2 \cup \cdots \cup R_M
  3. 互不重叠任意两个区域 $R_m$ 与 $R_{m'}$ 交集为空($\varnothing$),保证一个样本只落进一片叶子,预测值唯一。
    Rm∩Rm′=∅R_m \cap R_{m'} = \varnothing

特征阈值选择

分橙子时,张阿姨面临两道选择题:先问哪个特征?用多大的尺子分?她没有神通,办法是挨个试——用7厘米分一次,看看两筐齐不齐;再用6.5厘米分一次……把所有可能的尺子都试一遍,留下让堆内最齐整的那把。这个过程听起来笨拙,却是回归树最诚实的地方:每个内部节点都老老实实地枚举所有特征、所有候选阈值,用评分选最优。

这个“评分”就是下一节的均方误差(MSE)。在它登场之前,先解决一个更基础的问题:候选阈值从哪里来?对连续特征,我们当然不可能试遍所有实数。但仔细一想,真正有意义的切分点只存在于训练样本排序后的相邻值之间——只要两边的成员构成不变,切在哪一点都等价。所以 CART 约定:把特征值排序,取相邻两值的中点作为候选。

张阿姨试尺子的过程也是“排序—取中点”:7厘米、6.8厘米……她不会用 6.83 厘米这种刻度,因为相邻橙子之间没有更细的样本可区分,试了也白试。特征枚举同理——直径、颜色、产地挨个拿来当“第一问”试一遍,留下分得最齐的方案。

s∈{x(k)+x(k+1)2:k=1,2,…,n−1}\displaystyle s \in \left\{ \frac{x_{(k)} + x_{(k+1)}}{2} : k = 1, 2, \ldots, n-1 \right\}
候选切分阈值只取排序后相邻样本值的中点,既不会漏掉任何一种“分组方式”,又避免了在连续的实数轴上瞎找。
  1. 排序后的特征值$x_{(k)}$ 表示当前节点里第 k 小的特征取值,先把所有样本按该特征排序。
    x(1),x(2),…,x(n)x_{(1)}, x_{(2)}, \ldots, x_{(n)}
  2. 相邻值中点把 $x_{(k)}$ 和 $x_{(k+1)}$ 加起来除以 2,得到候选阈值——在相邻两个样本之间取中间位置切开。
    x(k)+x(k+1)2\frac{x_{(k)} + x_{(k+1)}}{2}
  3. 候选集合对 $k = 1$ 到 $n-1$ 全部取中点,最多 $n-1$ 个候选;排序之后复杂度可控,绝不无限搜索。
    {⋯:k=1,2,…,n−1}\{ \cdots : k = 1, 2, \ldots, n-1 \}

均方误差准则

张阿姨怎么判断一堆橙子“齐不齐”?她心里有个小算盘:记下这堆每个橙子的甜度,和这堆的平均甜度比一比,差得越多记一笔,把所有差值平方后加起来。这个平方和越小,说明大家越扎堆、越齐整。这个算盘,就是回归树分裂的准星。

在机器学习术语里,这个“齐整度”叫不纯度。分类树用基尼系数或信息熵,回归树用均方误差(MSE)。切分的目的是找到某个特征和阈值,让分裂出的左右两个子节点内部的 MSE 之和尽可能小——也就是让两个孩子堆都尽量“齐”。

其中左右两组的代表数就是各自的组内均值:

张阿姨的算盘珠子噼啪一响:7厘米这一刀让两筐的甜度差值平方和最小,她就锁死这把尺子。均方误差准则的朴素版本,不过如此。

min⁡j,s[∑i∈RL(j,s)(yi−yˉL)2+∑i∈RR(j,s)(yi−yˉR)2]\displaystyle \min_{j,s}\left[ \sum_{i \in R_L(j,s)} \left(y_i - \bar{y}_L\right)^2 + \sum_{i \in R_R(j,s)} \left(y_i - \bar{y}_R\right)^2 \right]
yˉL=1∣RL∣∑i∈RLyi,yˉR=1∣RR∣∑i∈RRyi\displaystyle \bar{y}_L = \frac{1}{|R_L|}\sum_{i \in R_L} y_i, \quad \bar{y}_R = \frac{1}{|R_R|}\sum_{i \in R_R} y_i
候选切分 (j, s) 的得分 = 左子节点残差平方和 + 右子节点残差平方和。得分最低的切分,就是张阿姨最终选中的那把尺子。
  1. 候选特征与阈值$j$ 是特征下标(比如“直径”),$s$ 是该特征的切分阈值,整个式子对所有 (j, s) 组合求最小值。
    min⁡j,s [⋯ ]\min_{j,s}\,[\cdots]
  2. 左子区域$R_L(j,s)$ 是满足 $x_j \le s$ 的样本集合,也就是切分后落入左筐的橙子。
    RL(j,s)={x:xj≤s}R_L(j,s) = \{ x : x_j \le s \}
  3. 左组均值$\bar{y}_L$ 是左组目标值的平均,切分之后左筐先用这个数代表自己。
    yˉL=1∣RL∣∑i∈RLyi\bar{y}_L = \frac{1}{|R_L|}\sum_{i \in R_L} y_i
  4. 右子区域$R_R(j,s)$ 是 $x_j > s$ 的样本,右筐照葫芦画瓢,也求自己的均值 $\bar{y}_R$。
    RR(j,s)={x:xj>s}R_R(j,s) = \{ x : x_j > s \}
  5. 残差平方求和左右两堆各自把“每个样本值减本堆均值”的平方加起来,总和最小意味着两堆内部差异最小、最齐整。

叶节点均值预测

分拣结束,张阿姨在每个筐里做什么?她从筐里拿出几个橙子,尝一下,甜度加起来除以个数,得到一个平均数,贴一张标签在筐上。以后再有橙子进店,按约定好的问题一路问下去,落进哪个筐,就按哪个筐的标签报价。

训练阶段的回归树也是这样:每片叶子把落进来的所有训练样本的目标值存下来,算一个均值作为自己的“标签”。预测阶段,新样本从根节点出发,根据每个节点的切分规则一路下沉,到达叶子后直接读出这个均值作为预测。整个过程不需要任何额外计算——规则是训练时定好的,预测只是“顺藤摸瓜”。

张阿姨贴的“均甜9分”标签,和这个公式做的事一模一样——几个样本的平均数,就是这一筐的答案。这也解释了回归树的预测为什么是“阶梯状”的:同一筐里的橙子共享同一个价,筐与筐之间才会跳变。

y^m=1nm∑i∈Rmyi\displaystyle \hat{y}_m = \frac{1}{n_m} \sum_{i \in R_m} y_i
叶子 m 的预测值,就是落入这片叶子的所有训练样本目标值的算术平均。
  1. 叶子样本数$n_m$ 是叶子 m 内训练样本的个数,相当于这只筐里橙子的数量。
    nm=∣Rm∣n_m = |R_m|
  2. 求和$\sum_{i \in R_m} y_i$ 把叶子内所有样本的真实目标值加总。
    ∑i∈Rmyi\sum_{i \in R_m} y_i
  3. 平均输出总和除以个数,得到该叶子的预测值 $\hat{y}_m$。

过拟合与剪枝

张阿姨若追求极致,把每筐橙子分到只剩一个——平均数就失去了意义:一筐只有一个橙子,平均甜度就是它本身,等于没用到任何规律。更糟的是,今天为那个虫眼橙子单独设的规则,明天完全不适用。她于是立下规矩:筐里至少要有几个橙子才算数,分堆层数不能太多;偶尔分完发现相邻两筐差不多,就倒回一筐重新合并。

树的语言里,这个风险叫过拟合:分裂层数(深度)越深,叶子越多,对训练数据拟合越精细,却也越容易把噪声当成规律——训练误差一路下跌,测试误差反而抬头。对策分两类。预剪枝在生长时叫停:限制最大深度 max_depth、要求叶子最少样本数 min_samples_leaf、要求切分前样本数下限。后剪枝则先让树长满,再自底向上合并那些“贡献不大”的分支,经典做法是代价复杂度剪枝。

α 就是张阿姨的管理耐心:α 小,她愿意多分几筐精耕细作;α 大,她嫌筐多占地儿,索性合并同类项。现实中,max_depth 和 min_samples_leaf 是最常用的两个旋钮,几乎每个工业级的树模型都靠它们兜底。

Cα(T)=∑m=1∣T∣∑i∈Rm(yi−yˉm)2+α ∣T∣\displaystyle C_\alpha(T) = \sum_{m=1}^{|T|} \sum_{i \in R_m} \left(y_i - \bar{y}_m\right)^2 + \alpha\,|T|
代价复杂度给“叶子数量”加了一笔税(α|T|)。α 越大,树越不敢多长叶子,整体就越小、越简朴。
  1. 树上每片叶子$|T|$ 表示树的叶子总数,对每一片叶子 $m$ 都要算一笔账。
    m=1,2,…,∣T∣m = 1, 2, \ldots, |T|
  2. 拟合误差叶子 $m$ 内样本与均值 $\bar{y}_m$ 的残差平方和,衡量这片叶子的“不齐”程度。
    ∑i∈Rm(yi−yˉm)2\sum_{i \in R_m} \left(y_i - \bar{y}_m\right)^2
  3. 复杂度惩罚$\alpha\,|T|$ 是叶子数量的罚金,每多一片叶子就多交一份 α 的税。
    α ∣T∣\alpha\,|T|
  4. 总代价拟合误差与复杂度惩罚相加;α 大则多叶不划算,树被裁剪得更小,以减少过拟合。

回归树特点

张阿姨的分拣法在菜市场流传开,大家总结出三大好处。一,顾客问“凭什么这筐卖得贵”,她能指着筐解释“皮光滑、直径大,甜度平均9分”——规则摆得明明白白。二,甜度和直径不是直线关系,她照样分得准。三,昨天用厘米今天用英寸,量出来的大小顺序不变,分拣结果一丝不差。

翻译成机器学习的语言,这三点分别是:可解释性、非线性拟合、尺度不变。树的每条根到叶子的路径就是一条 if-then 规则,可以写成大白话;分段常数预测函数能逼近各种复杂的阶梯关系;特征做任何单调变换(归一化、取对数),只要顺序不变,分裂结果和预测就完全不变——所以回归树通常不需要特征缩放。此外,数值特征切阈值、分类特征做二分,它还能天然混合多种类型。

当然,缺点同样明显:单棵树不稳定,训练数据稍有扰动,结构可能大变;外推能力差,预测永远落在训练目标值的范围内;单棵树方差大,预测“抖”。这三点,正是集成方法登场的理由。

张阿姨的每一只筐,就是一段常数:同一筐里的橙子报同一个价。树不会在筐与筐之间画平滑的过渡线,它只会干脆利落地“跳价”,而这种跳变,恰恰抓住了非线性关系。

f^(x)=∑m=1My^m⋅1 ⁣(x∈Rm)\displaystyle \hat{f}(x) = \sum_{m=1}^{M} \hat{y}_m \cdot \mathbf{1}\!\left(x \in R_m\right)
整个回归树的预测函数,是 M 片叶子各自输出的均值,用指示函数挑出当前样本命中的那一片。
  1. M 片叶子$M$ 是叶子总数,预测由所有叶子的贡献求和构成。
    ∑m=1M\sum_{m=1}^{M}
  2. 指示函数$\mathbf{1}(x \in R_m)$ 在样本落入叶子 m 时取 1,否则取 0——只有一片叶子“发声”。
    1(x∈Rm)\mathbf{1}(x \in R_m)
  3. 叶子输出$\hat{y}_m$ 是叶子 m 的均值,对应“这筐橙子的均甜标签”。
    y^m\hat{y}_m
  4. 分段常数其他项全部归零,只剩命中叶子贡献一个常数——整体是一个阶梯状的分段常数函数。

应用与扩展

日子久了,张阿姨发现单靠自己分拣会“手抖”:今天进的这批橙子品质不同,最优点就漂移。隔壁摊主老王、小李也学会了这套分拣法,大家一合计:五人各自分各自的,最后把五个人的预测甜度取个平均——谁偶尔看走眼,也影响不了大局。这就是把单棵“草根树”变成“森林”的朴素智慧。

工业界的回归树也几乎从不单打独斗,更多时候是被当作基学习器装进集成模型。随机森林对训练样本做有放回抽样,每棵树只在随机挑选的特征子集上分裂,最后把多棵树的预测平均;梯度提升树则让每棵新树去拟合前面所有树的残差(真实值减去当前预测),一步步逼近目标。两者的大楼,都盖在回归树的地基上。

在房价预测、零售销量预测、广告出价预测等场景,这些集成模型常年占据榜首。理解回归树的切分逻辑、MSE 准则和剪枝策略,就是读懂它们的第一块敲门砖。

张阿姨和老王们七嘴八舌各有判断,但最终报给顾客的,是五个人甜度预测的平均值——这比任何一个人的“单口相声”都可信。回归树是那颗草根种子,集成才是长成的大树。

y^=1B∑b=1Bf^b(x)\displaystyle \hat{y} = \frac{1}{B} \sum_{b=1}^{B} \hat{f}_b(x)
随机森林把 B 棵回归树的预测取平均,用“少数服从多数”抵消单棵树的方差。
  1. B 棵树$B$ 是森林中回归树的棵数,每棵树都在不同的样本/特征子集上长大。
    b=1,2,…,Bb = 1, 2, \ldots, B
  2. 每棵树的预测$\hat{f}_b(x)$ 是第 b 棵树对样本 x 输出的回归值(分完筐之后的均值标签)。
    f^b(x)\hat{f}_b(x)
  3. 取平均所有树的结果加总除以 B,得到更稳、方差更小的集成预测。
    1B∑b=1Bf^b(x)\frac{1}{B}\sum_{b=1}^{B} \hat{f}_b(x)

AI 应用场景

房地产估价平台

阶段:特征工程与模型训练、模型上线与解释

解决的问题:传统估价依赖经纪人的经验和主观判断,速度快却难解释“凭什么这个价”。回归树把估价变成一叠“如果-那么”规则:切分全程透明,每片叶子的均值就是定价依据,客户质疑时能当场拆解;它还能抓住“老破小”与“次新房”截然不同的非线性定价逻辑,这是线性模型难以企及的。

具体案例:某房产平台用面积、房龄、楼层、距地铁距离训练回归树。模型长出一棵规则树:“房龄≤5年 且 面积≥90㎡ → 均价5万2/㎡”;“房龄>20年 且 距地铁≤800m → 均价4万1/㎡”。经纪人向客户汇报定价时说的两条理由,就是树上的两条路径。

零售销量预测与补货

阶段:数据清洗与特征构建、模型训练与预测

解决的问题:销量与促销、季节、天气的关系高度非线性,线性模型难以刻画“大促爆发、平日平淡”的阶梯效应。回归树按“是否大促→去年同款销量→价格区间”层层切分,每个场景给一个基线预测,供应链据此备货。

具体案例:某连锁超市在双11前用回归树预测上万 SKU 的销量:先按“是否大促”切一刀,再按“去年同款是否破千件”切第二刀,叶子输出各档预测均值,自动生成补货单。上线后缺货率下降约 18%,滞销库存同步减少。

GBDT 的基学习器

阶段:模型集成与残差拟合

解决的问题:单棵回归树方差大、稳定性差,直接上线风险高。梯度提升树让每一棵新树去拟合前面所有树的残差,数棵浅回归树逐级叠加,把“分筐均值”升级成“逐步纠错”。

具体案例:广告投放场景用 GBDT 预测用户点击后的消费金额(连续值),数百棵浅回归树逐棵拟合预测残差,把单棵树的 MSE 从 0.31 压到 0.19,出价策略随之更精准。

Python 演示

python72 行
import numpy as np  class RegressionTree:    def __init__(self, max_depth=4, min_samples_leaf=5):        self.max_depth = max_depth        self.min_samples_leaf = min_samples_leaf        self.tree = None     def _mse(self, y):        if len(y) == 0:            return 0.0        return float(np.mean((y - np.mean(y)) ** 2))     def _split_loss(self, y_left, y_right, n):        return (len(y_left) * self._mse(y_left) + len(y_right) * self._mse(y_right)) / n     def _best_split(self, X, y):        n, d = X.shape        best_loss = float("inf")        best_j, best_s = None, None        for j in range(d):            thresholds = np.unique(X[:, j])            for s in (thresholds[:-1] + thresholds[1:]) / 2.0:                mask = X[:, j] <= s                if mask.sum() < self.min_samples_leaf or (n - mask.sum()) < self.min_samples_leaf:                    continue                loss = self._split_loss(y[mask], y[~mask], n)                if loss < best_loss:                    best_loss, best_j, best_s = loss, j, float(s)        return best_j, best_s     def fit(self, X, y):        self.tree = self._build(X, y, 0)        return self     def _build(self, X, y, depth):        if depth >= self.max_depth or len(y) < 2 * self.min_samples_leaf:            return {"value": float(np.mean(y))}        j, s = self._best_split(X, y)        if j is None:            return {"value": float(np.mean(y))}        mask = X[:, j] <= s        return {            "feature": j,            "threshold": s,            "left": self._build(X[mask], y[mask], depth + 1),            "right": self._build(X[~mask], y[~mask], depth + 1),        }     def _predict_one(self, x, node):        if "value" in node:            return node["value"]        if x[node["feature"]] <= node["threshold"]:            return self._predict_one(x, node["left"])        return self._predict_one(x, node["right"])     def predict(self, X):        if self.tree is None:            raise ValueError("Please fit first")        return np.array([self._predict_one(x, self.tree) for x in X])  if __name__ == "__main__":    X = np.array([[45], [55], [60], [70], [80], [95], [110], [130], [150], [170]], dtype=float)    y = np.array([120, 135, 150, 165, 190, 210, 245, 280, 320, 360], dtype=float)     model = RegressionTree(max_depth=3, min_samples_leaf=2)    model.fit(X, y)    pred = model.predict(X)    print("预测房价(万元):", pred)    print("训练MSE:", np.mean((y - pred) ** 2))
目的:从零实现回归树的建树、切分与预测,演示“最小化加权子节点均方误差”如何转化为可运行的递归逻辑。
  1. thresholds = np.unique(X[:, j])对该特征排序并去重,得到候选切分值。
  2. for s in (thresholds[:-1] + thresholds[1:]) / 2.0:取相邻值中点作为候选阈值,对应“试尺子”。
  3. return (len(y_left) * self._mse(y_left) + len(y_right) * self._mse(y_right)) / n加权子节点 MSE,是给每次切分打的分。
  4. if mask.sum() < self.min_samples_leaf左右两边样本都不能太少,否则这刀切得太碎。
  5. if loss < best_loss:遍历所有特征和阈值后,保留得分最低的切分。
  6. if "value" in node:叶子节点没有子分支,直接返回训练样本均值。
  7. return self._predict_one(x, node["left"])预测时按规则沿左分支递归下落,直到命中叶子。

常见误区

误区教材把“分类”和“回归”分成两章,名字又不同,初学者常以为回归树和分类树是两种完全独立的模型家族,需要分别学两套底层理论。

正解它们同属 CART 的同一骨架:都是递归二分 + 叶子出结果。区别只在分裂评分标准(回归用均方误差,分类用基尼系数或熵)和叶子输出(回归出均值,分类出类别)。学会回归树的切分逻辑,分类树的核心也就掌握了一大半——张阿姨分橙子是甜度,分苹果是品相,手法一模一样。

为何常见:教材章节和 API 名称把两者割裂展示,容易让人误以为底层实现也完全不同。

误区“既然能预测新样本,那面积 500 平米、训练数据里从没出现过的超大户型,回归树也应该能给个合理报价吧?”

正解不能。回归树的预测是分段常数,任何新样本都要落进某片叶子,被输出为该叶子训练样本的均值。测试数据落在训练范围之外时,没有对应叶子,预测值只会“贴最近叶子的均值”,不会像线性回归那样延伸出去。树擅长插值,不擅长外推。

为何常见:学了线性回归能外推,再学树模型时容易把“预测”理解成可延伸到训练范围之外。

误区“训练误差随深度一路下降,那把树长到最深,测试效果应该也最好。”

正解树过深会把噪声也记住,训练误差很低但测试误差反弹,这就是过拟合。需要用最大深度、最小叶子样本数做预剪枝,或用代价复杂度做后剪枝,让叶子有足够样本支撑、结构足够简朴,泛化才会好。张阿姨也不会把每筐分到只剩一个橙子。

为何常见:训练集上棵树越深越“完美拟合”,直观上“拟合得好=表现好”,忽略了训练与测试的鸿沟。

误区“别的模型都要归一化,回归树也应该 Z-score 标准化,否则量纲大的特征会占便宜。”

正解回归树按单特征阈值切分,只依赖特征取值的大小顺序;任何单调变换(线性缩放、取对数)只会改变阈值数值,分组结果和预测值完全不变。需要缩放的 KNN、SVM、线性回归等基于距离或梯度的模型,树的机制根本不做距离计算,自然不要求缩放。

为何常见:把深度学习/线性模型的经验迁移到树上,而忽略了树的切分机制与距离度量无关。

面试题

Q1. 回归树叶子节点对样本的预测值是如何得到的?

单选题 · easy

  • A.取整棵训练集的全局均值
  • B.取叶子内样本的目标均值← 正确答案
  • C.取叶子内目标值的中位数
  • D.取根节点的初始预测值

答案:B。回归树每片叶子保存落入其中的训练样本目标值均值,预测时直接输出该均值。全局均值是根节点还没分裂时的初始预测;CART 默认不取中位数;根节点预测只是树的起点而非叶子输出。

Q2. 回归树分裂时最常用的评分准则是哪个?

单选题 · easy

  • A.基尼不纯度指数最小
  • B.信息熵增益最大
  • C.均方误差加权和最小← 正确答案
  • D.交叉熵损失最小化

答案:C。基尼系数、信息熵和交叉熵都针对离散标签的分类任务;回归目标连续,用均方误差衡量组内离散程度,选子节点加权 MSE 之和最小的切分。

Q3. 为什么回归树通常不需要特征归一化?

单选题 · easy

  • A.切分只依赖特征排序位置← 正确答案
  • B.树内部自带标准化层
  • C.特征必须服从正态分布
  • D.模型会自动丢弃大数值

答案:A。树的切分比较的是“特征是否小于阈值”,只依赖取值大小顺序。任何单调变换只改变阈值数值,不改变样本分组,也不改变叶子的预测结果,因此归一化对回归树没有影响。

Q4. 回归树的预测函数在数学上属于哪种形式?

单选题 · mid

  • A.特征线性加权求和函数
  • B.光滑多项式逼近函数
  • C.分段常数预测函数← 正确答案
  • D.指数衰减逼近函数

答案:C。输入空间被切成互不重叠的矩形叶子区域,每个区域输出固定均值,所以整体是分段常数函数;它不是线性的、光滑的,也不涉及指数形式。

Q5. 连续特征上候选切分阈值通常取自哪里?

单选题 · mid

  • A.特征取值的最大值
  • B.随机抽样得到的一个数
  • C.经验分布的分位数
  • D.排序后相邻值中点← 正确答案

答案:D。对连续特征排序后,相邻两个样本值之间的任何点产生的分组完全相同,CART 取相邻值中点作为候选阈值,既减少搜索量又不遗漏任何分组可能。

Q6. 下列哪些属于回归树的优点?

多选题 · mid

  • A.模型结果容易解释← 正确答案
  • B.能拟合非线性关系← 正确答案
  • C.对异常值完全免疫
  • D.支持混合类型特征← 正确答案

答案:ABD。树的每条路径都是可复述的规则,分段常数能拟合非线性关系,数值特征切阈值、类别特征做二分,天然支持混合类型。但“完全免疫异常值”是错的——叶子均值仍会受到离群样本的拉扯。

Q7. 代价复杂度剪枝中 α 增大时,树的变化趋势是?

单选题 · hard

  • A.叶子数量逐渐减少← 正确答案
  • B.叶子数量逐渐增多
  • C.树的深度必然加深
  • D.训练误差必然降低

答案:A。代价复杂度 Cα = 拟合误差 + α×叶子数。α 越大,每多一片叶子的惩罚越重,树被剪得越小、叶子越少。训练误差通常不降反升,但换来更小的结构风险,提升泛化能力。

Q8. 下列哪些措施能有效抑制回归树过拟合?

多选题 · hard

  • A.限制树的最大深度← 正确答案
  • B.提高最小叶子样本数← 正确答案
  • C.生长完成后后剪枝← 正确答案
  • D.增加更多训练特征

答案:ABC。限制深度、提高最小叶子样本数、自底向上的后剪枝都能减少叶子数和复杂度,直接对抗过拟合。增加特征并不能保证抑制过拟合,反而可能给噪声提供更多切分机会。

Q9. 回归树可作为哪些集成模型的基学习器?

多选题 · mid

  • A.随机森林← 正确答案
  • B.梯度提升树← 正确答案
  • C.K 近邻回归
  • D.岭回归模型

答案:AB。随机森林对样本和特征做随机采样后平均多棵树的预测,梯度提升树让每棵新树拟合残差,两者的基学习器都是回归树;K 近邻和岭回归不是树模型。

Q10. 与线性回归相比,回归树在预测上的最典型局限是?

单选题 · extreme

  • A.输出的预测值必然不连续
  • B.无法处理多个数值特征
  • C.对训练范围外无法外推← 正确答案
  • D.计算复杂度恒为指数级

答案:C。分段常数只在训练分布内有效,训练范围外没有任何叶子覆盖,树无法外推;线性回归虽可能外推失真,但至少能给出解析延拓。“预测不连续”是分段常数的特点而非缺陷;树完全支持多维特征;训练复杂度也远不是恒定指数级。