很多人第一次见决策树,会觉得它"高级",其实它是所有机器学习模型里最好懂的一个:一棵自动学出来的 if-else 判断树。你不用懂复杂的数学,也能直接读出它"为什么这么判",所以它被称为典型的"白盒"模型。(个人主页:https://wobuhuang.com)

在这里插入图片描述

一、它长什么样:内部节点 = 提问,叶子 = 类别

以"是否适合户外运动"为例:

  • 内部节点:一次提问,比如"天气是什么?"“湿度高吗?”
  • :提问的答案,比如 晴 / 雨
  • 叶子:最终的类别,适合 / 不适合

从根一路问到叶子,就得到预测结果。

二、每个节点该用哪个特征分裂?信息增益 vs 基尼

树长出来的核心问题是:这一层该挑哪个特征来提问? 答案是——挑最能把不同类别区分开的那个。衡量"区分能力"的常见指标有三种:

  • 信息增益(ID3):分裂后"纯度"提升了多少,本质是熵下降了多少。
  • 信息增益比(C4.5):修正 ID3 偏爱"取值多"特征的毛病。
  • 基尼指数(CART):另一种纯度度量,做二叉分裂。
    在这里插入图片描述

三、逐层分裂,纯度一步步提升

构建是一个递归过程:在全部数据上,“天气"信息增益最大 → 选它做根节点的提问;按取值(晴 / 雨)分裂成两堆;每一堆再在自己那份数据上重新挑最好的特征继续问。晴天这支选"湿度”,雨天这支选"有风",直到某堆基本同类(纯),就停下成为叶子。
在这里插入图片描述

四、预测路径:新样本一路走到叶子

训练完成后预测非常直观:一个新样本"晴 + 湿度正常",沿着树走——天气 = 晴 → 湿度 = 正常 → 落到"适合"这个叶子。整条路径清清楚楚,这就是白盒模型的魅力。
在这里插入图片描述

五、完整 C++ 实现(带注释)

// 递归构建一棵决策树
// data:当前节点上的数据;feats:还能用来分裂的特征集合
Node* build(Data data, set<Feature> feats) {
  if (pure(data) || feats.empty())          // 已纯 / 无特征可用
    return leaf(majority_class(data));       //   → 叶子(取多数类)

  Feature best = argmax_gain(data, feats);   // 选信息增益最大的特征
  Node* node = new Node(best);

  for (auto v : values(best))                // 按该特征的每个取值分裂
    node->child[v] =                         // 子节点 = 对子集递归构建
        build(subset(data, best, v),         //   subset:取出该取值的数据
              feats - best);                 //   该特征用过后从集合移除

  return node;                               // 返回构建好的(子)树
}

复杂度:训练约 O(n · 特征数 · 深度),空间 O(节点数)。预测就是从根走到叶子,深度有多深就问几次。

六、过拟合与剪枝

决策树最大的毛病是过拟合:如果让树无限生长,它能把训练集每个样本都背下来,训练误差降到 0,可一到新数据就崩。它还对噪声/小扰动敏感,数据稍变树就可能大变(高方差)。对策:

  • 预剪枝:限制最大深度、限制叶子最小样本数,长到一定程度就停。
  • 后剪枝:先长全,再把对验证集没帮助的分支砍掉。

七、小结

决策树 = 自动学出来的 if-else,靠信息增益 / 增益比 / 基尼挑分裂特征,逐层分裂提升纯度,预测就是走一条路径到叶子。单棵树往往不够强,实战常用随机森林、GBDT/XGBoost 把很多棵弱树集成起来。

想看决策树一层层长出来、再走一条预测路径的动画?在「码路星球」里全程免费看。(个人主页:https://wobuhuang.com)

决策树 / 机器学习 / 信息增益 / 基尼系数 / C++ / 算法可视化 / CART / ID3

更多推荐