ML:决策树的基本原理与实现
2026/4/28 14:38:20 网站建设 项目流程

在机器学习中,并不是所有模型都通过一个连续的数学公式来表达输入与输出之间的关系。有一类方法的思路更接近人类的规则判断:先提出一个问题,根据答案把样本分到不同分支;再继续提出下一个问题,直到得到最终结论。决策树(Decision Tree)正是这种思想的典型代表。

一、决策树的基本思想

决策树的核心思想是:通过一系列逐步的条件判断,把样本空间不断划分为更“纯”的区域。

例如,在一个分类问题中,模型可能先判断“某个特征是否小于某个阈值”;如果是,就进入左分支,否则进入右分支。进入下一层后,再根据新的条件继续划分。最终,每个样本都会落入某个叶节点,而叶节点中保存的,就是该区域对应的类别或数值预测。

从直观上看,决策树完成的是这样一件事:

• 输入:一组特征

• 过程:不断提出划分问题

• 输出:类别标签或连续数值

• 目标:让每次划分都尽量提升节点内部的一致性

图 1 决策树的基本预测过程

决策树可以被看作是对目标变量的一种分段常数近似(piecewise constant approximation):不同区域由不同叶节点负责预测,树越深,规则越复杂,拟合能力也越强。

二、树结构与样本划分

决策树通常由以下几部分组成:

• 根节点:整棵树的起点,包含全部训练样本

• 内部节点:表示某一次基于特征与阈值的划分

• 分支:表示条件判断的不同结果

• 叶节点:表示最终预测结果所在位置

在分类树中,叶节点通常对应某一类别,或某一类别概率占优的区域;

在回归树中,叶节点通常对应一个数值预测。

这说明,决策树并不是先写出一个完整公式,再去一次性拟合所有样本;它更像是在不断做局部决策:当前这批样本,应该依据哪个特征、以哪个阈值来切分,才更有利于后续预测?

三、分类树的划分准则

1、为什么要定义“节点纯度”

在分类问题中,一次好的划分,应该使得划分后的节点尽量只包含少数类别,甚至只包含一种类别。

因此,决策树需要一个标准来衡量:当前节点“混杂”到什么程度,以及一次划分能让这种混杂减少多少。这就引出了节点纯度与划分质量的问题。

2、基尼不纯度

分类树中常见的划分准则(criterion)之一是基尼不纯度(Gini Impurity),也称“基尼系数”(Gini Index)。

若当前节点中共有 K 个类别,第 k 类样本所占比例为pₖ,则基尼不纯度可写为:

它的含义是:节点越混杂,基尼不纯度越大;节点越纯,基尼不纯度越小。

3、信息熵

另一个常见准则是信息熵(Entropy):

它同样用于衡量节点内部类别分布的混乱程度。熵越大,说明类别越混杂;熵越小,说明节点越纯。

Scikit-learn 的 DecisionTreeClassifier 支持用 criterion 参数指定划分质量函数,当前支持的典型选项包括 "gini"、"entropy" 与 "log_loss"。默认值为 "gini"。

4、划分的目标

无论使用基尼不纯度还是信息熵,其核心目的都是一样的:选择那个能使子节点更纯的划分方式。

也就是说,在每一个节点,算法都会尝试不同特征与不同阈值的组合,并选出能够最大程度降低不纯度的那一次划分。

因此,决策树并不是随意地“画分支”,而是在每一步都依据明确的优化标准进行局部最优选择。

四、经典决策树算法:ID3、C4.5 与 CART

在决策树生长过程中,如何基于基尼不纯度、信息熵这些度量指标来选择最优划分属性?不同算法给出了不同的策略。

ID3、C4.5 和 CART 是决策树发展史上的三个里程碑算法。它们都采用贪心、自顶向下递归分治的方式构建树,但选择分裂属性的准则不同。

1、ID3 与信息增益

ID3 算法使用信息增益(Information Gain) 作为属性选择度量。

信息增益基于信息论中的熵概念。

数据集 D 的熵定义为:

其中pᵢ是第 i 类样本的比例。熵越大,数据集越“混乱”。

若按属性 A 将 D 划分为 v 个子集 D₁, D₂, …, Dᵥ ,则划分后的期望熵为:

信息增益即为划分前后熵的减少量:

ID3 选择信息增益最大的属性进行分裂。但信息增益倾向于取值较多的属性(如用户 ID),容易过拟合。

2、C4.5 与增益率

C4.5 是 ID3 的改进版,使用增益率(Gain Ratio) 来校正信息增益的偏好。

增益率在信息增益的基础上,除以属性自身的信息量(称为分裂信息),从而惩罚取值过多的属性。

3、CART 与基尼不纯度

CART(Classification and Regression Tree)算法既可用于分类也可用于回归。分类时使用基尼不纯度,回归时使用均方误差(MSE)。

CART 生成的树是二叉树(每个节点只有两个分叉),而 ID3/C4.5 可以生成多叉树。

在 Scikit-learn 的 DecisionTreeClassifier 中:

• criterion="entropy" 对应 ID3 的信息增益思想

• criterion="gini" 对应 CART 的分类准则

scikit-learn 的实现默认采用 CART 优化版本(二叉树 + 基尼不纯度 / MSE),同时通过 splitter="best" 或 "random" 等参数提供灵活性。

五、回归树的划分准则

1、回归树不再关心类别纯度

在回归问题中,目标值是连续数值,而不是类别标签。因此,回归树无法再使用基尼不纯度或信息熵这类分类准则。

此时,模型关心的问题变成了:怎样划分样本,才能使每个子节点中的数值波动尽量小?

2、平方误差与方差缩减

Scikit-learn 的 DecisionTreeRegressor 默认使用 "squared_error" 作为划分准则。该准则对应均方误差意义下的划分质量,也可理解为基于方差缩减来选择切分方式。这一准则本质上最小化 L2 损失,并以每个叶节点中的均值作为预测值。

直观地说,一次好的划分,应该让划分后的每个子节点内部目标值更集中,波动更小。

3、回归树叶节点的预测

如果某个样本最终落入某个叶节点,回归树通常会使用该叶节点中训练样本目标值的平均值作为预测输出。

因此,回归树可以看作是在不断划分空间,最后对每个小区域给出一个局部常数预测。

六、决策树如何生长

1、递归划分

决策树通常采用递归方式生长:

• 从根节点开始

• 寻找当前最优划分

• 生成左右子节点

• 对每个子节点重复同样过程

• 直到满足停止条件

常见的停止条件包括:

• 达到最大深度

• 节点样本数过少

• 节点已经足够纯

• 继续划分带来的收益太小

2、树越深,模型越复杂

树的深度越大,说明划分次数越多,模型能够表示的规则也越复杂。

图 2 树深度与模型复杂度的关系

Scikit-learn 的控制树大小的参数默认值通常会生成完全生长且未剪枝的树,它们在某些数据集上可能非常大,因此应通过 max_depth、min_samples_leaf 等参数控制复杂度与内存消耗。

这说明,决策树虽然表达能力强,但也非常容易过拟合。

3、剪枝思想

为了防止树长得过深、过复杂,可以对树进行约束或剪枝。

Scikit-learn 支持最小成本复杂度剪枝(minimal cost-complexity pruning),相关参数是 ccp_alpha。当 ccp_alpha=0.0 时默认不做剪枝;当它增大时,模型会倾向于选择更简单的子树。

七、决策树的推理:树是如何做出预测的

当决策树训练完成后,对一个新样本进行预测的过程非常直观:从根节点出发,在每个内部节点根据特征与阈值的比较结果选择分支,一路走到叶节点,然后将该叶节点存储的预测值(分类时是多数类,回归时是均值)作为输出。

1、一次完整的决策过程

用一个简单的例子说明。假设一棵用于判断“今天是否适合户外运动”的决策树,根节点的规则是:

如果 天气 == “晴天” → 进入左子节点否则(阴天/雨天) → 进入右子节点

左子节点继续判断:

如果 温度 > 28℃ → 预测“不适合”否则 → 预测“适合”

现在来了一个新样本:天气=晴天,温度=30℃。预测过程如下:

(1)从根节点开始,检查“天气”:晴天 → 走向左子节点。

(2)到达左子节点,检查“温度”:30℃ > 28℃ → 走向“不适合”叶节点。

(3)叶节点给出预测:“不适合户外运动”。

整个过程就是一条从根到叶的路径,每一步的判断规则都是明确的“如果……那么……”。

2、特征与阈值在决策路径中的作用

每个内部节点上的特征决定了该节点关注样本的哪一个属性,而阈值(分类树中离散特征则是取值集合)划定了分支的边界。

靠近根节点的特征通常是全局影响力较大的变量(如“天气”比“是否有风”更影响户外运动决策)。

越靠近叶节点的特征,负责的是更细粒度、更局部的区分(比如只有在晴天这个前提下,温度才变得关键)。

这种分层决策模式,让决策树天然具有可解释性:你可以完整地回溯一个预测背后的所有判断条件。

3、与线性模型的区别

线性模型通过一组系数给出一个全局公式:

它适合回答“特征每变化一个单位,预测值如何变化”,但不易解释单个样本的具体决策路径。

决策树则走另一条路:它不给出连续公式,而是为每个样本定制一条逻辑路径。

因此,决策树更擅长回答:

• 为什么这个样本被判为 A 类而不是 B 类?

• 改变哪个特征值,会导致预测结果翻转?

当然,代价是决策树的预测在输入空间中是分段常数的,不够光滑,且在小扰动下路径可能突变(稳定性不如线性模型)。

4、在代码中观察决策路径

在 Scikit-learn 中,训练后的决策树可以通过 tree_.decision_path(X) 获取样本走过的节点索引。例如(接下一节的鸢尾花分类代码):

# 假设已经训练好 modelleaf_ids = model.apply(X_test) # 返回每个样本落入的叶节点编号paths = model.decision_path(X_test) # 返回稀疏矩阵,表示每个样本经过的节点 # 查看第一个测试样本的路径print(f"叶节点编号: {leaf_ids[0]}") # 输出每个样本经过的节点索引(从根节点到叶节点的完整路径)print(f"经过的节点: {paths[0].indices}")

输出类似 [0 2 3 4](具体路径取决于树的实际结构,此处仅为示例),表示该样本从根节点 0 出发,依次经过节点 2、节点 3,最终到达叶节点 4。

结合之前打印的树结构,就能还原完整的决策逻辑。

八、Python 实现:决策树分类示例

下面用鸢尾花数据集演示决策树分类的基本实现方式。DecisionTreeClassifier 用于分类,支持多种划分准则与树规模控制参数。

# 导入所需模块from sklearn.datasets import load_iris # 加载鸢尾花数据集的函数from sklearn.model_selection import train_test_split # 数据集划分函数from sklearn.tree import DecisionTreeClassifier # 决策树分类器 # 1. 加载数据iris = load_iris() # 加载鸢尾花数据集,返回一个 Bunch 对象(类似字典)X = iris.data # 特征数据:150行4列的二维数组,4个特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度y = iris.target # 标签数据:一维数组,长度为150,值0、1、2分别代表三种鸢尾花(山鸢尾、变色鸢尾、维吉尼亚鸢尾) # 2. 划分训练集与测试集# train_test_split 将数据集随机划分为训练集和测试集# 参数说明:# X, y: 特征和标签# test_size=0.2: 测试集占总数据的20%(即30个样本),训练集占80%(120个样本)# random_state=42: 随机种子,固定划分方式,确保代码每次运行结果一致X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42) # 3. 创建分类树(决策树分类器)# DecisionTreeClassifier 参数解释:# criterion="gini": 节点分裂时使用基尼不纯度(Gini impurity)作为不纯度度量;也可选 "entropy"(信息熵)# max_depth=3: 限制树的最大深度为3层,防止过拟合(默认不限制,会完全生长直到所有叶子纯正或样本数过少)# random_state=42: 控制分裂时的随机性(当特征评估值相同时),保证结果可复现model = DecisionTreeClassifier( criterion="gini", max_depth=3, random_state=42) # 4. 训练模型# fit 方法基于训练集构建决策树:递归地选择最佳特征和阈值进行分裂,直到满足停止条件(达到最大深度或节点纯正)model.fit(X_train, y_train) # 5. 预测# predict 方法对测试集每个样本,从根节点开始依照树的分支规则走到叶节点,返回该叶节点的多数类作为预测类别y_pred = model.predict(X_test) # 输出前10个预测结果,直观检查模型的表现print("前 10 个预测结果:", y_pred[:10]) # score 方法返回测试集上的分类准确率(预测正确的样本数 / 总样本数)print("测试集得分:", model.score(X_test, y_test)) # get_depth 返回决策树的实际深度(根节点深度为0,最深叶子节点的深度)print("树的深度:", model.get_depth()) # get_n_leaves 返回决策树的叶节点数量print("叶节点数量:", model.get_n_leaves())

这段代码展示了决策树分类的基本工作流:

1、生成或加载数据

2、划分训练集与测试集

3、创建分类树

4、用 fit 学习划分规则

5、用 predict 输出类别结果

在这里,max_depth=3 用于显式限制树的复杂度;get_depth() 与 get_n_leaves() 可帮助观察树的规模。

Scikit-learn 的树结构也可以进一步通过可视化工具或 tree_ 属性进行分析。其中根节点编号通常为 0,树的节点数、最大深度等信息也可以从 tree_ 属性获得。

九、Python 实现:决策树回归示例

下面再给出一个一维回归示例,用来说明回归树如何通过分段常数的方式逼近连续函数。

Scikit-learn 的回归树示例展示了:当树深度过大时,模型会学到训练数据中的细小波动乃至噪声,从而出现过拟合。

import numpy as npfrom sklearn.model_selection import train_test_split # 用于划分训练集和测试集from sklearn.tree import DecisionTreeRegressor # 决策树回归器 # 1. 构造一维非线性数据rng = np.random.RandomState(42) # 创建随机数生成器,固定种子42,保证每次运行生成的噪声相同X = np.linspace(-3, 3, 120).reshape(-1, 1) # 生成120个在[-3, 3]上均匀分布的点,并转换为列向量(特征)# y = sin(x) + 噪声,模拟非线性回归问题# np.sin(X[:, 0]):对每个x计算正弦值(X是二维数组,取第一列)# 0.3 * rng.normal(size=120):添加均值为0、标准差为0.3的高斯噪声,使数据更贴近真实场景y = np.sin(X[:, 0]) + 0.3 * rng.normal(size=120) # 2. 划分训练集与测试集# test_size=0.2:测试集占20%(24个样本),训练集占80%(96个样本)# random_state=42:固定随机划分方式,便于结果复现X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42) # 3. 创建回归树(决策树回归器)# DecisionTreeRegressor 参数解释:# criterion="squared_error": 分裂时使用均方误差(MSE)作为衡量节点不纯度的指标,即最小化预测值与真实值的平方差# max_depth=4: 限制树的最大深度为4层,防止过拟合(如果完全生长会学习到噪声)# random_state=42: 控制分裂时的随机性(当多个特征/阈值给出相同的MSE增益时),确保可复现性model = DecisionTreeRegressor( criterion="squared_error", max_depth=4, random_state=42) # 4. 训练模型# fit 方法基于训练集构建回归树:递归地选择最佳特征和划分阈值,使子节点的均方误差最小化,直到达到max_depth或节点样本数过少model.fit(X_train, y_train) # 5. 预测# predict 方法对测试集每个样本,从根节点开始根据特征值沿树走到叶子节点,返回该叶子节点上所有训练样本的均值作为预测值y_pred = model.predict(X_test) # 打印前5个样本的真实值与预测值,保留3位小数,直观对比回归效果for i in range(5): print(f"真实值: {y_test[i]:.3f} 预测值: {y_pred[i]:.3f}")

这个示例说明,在回归问题中,决策树不是去拟合一条连续光滑曲线,而是通过不断划分输入空间,在每个局部区域给出一个常数预测。树越深,这种分段近似会越细,但同时也更容易把噪声学进去。

十、决策树适用场景与主要局限

1、适用场景

决策树较适合以下情况:

• 既可能是分类任务,也可能是回归任务

• 希望模型具有较好的可解释性

• 特征之间可能存在非线性关系或复杂交互

• 不希望预处理过于复杂

• 希望快速建立一个直观的基线模型

决策树的一项优势是:通常需要的数据准备较少,不必像某些方法那样强依赖标准化或哑变量编码。

2、主要局限

决策树虽然直观,但也并不是万能方法。

• 容易过拟合:树过深时,很容易学习到训练数据中的噪声

• 稳定性不足:数据稍有变化,树结构就可能明显改变

• 分段常数近似较粗糙:在某些连续问题上,预测可能不够平滑

• 贪心划分不保证全局最优:每一步都选局部最优划分,不代表整棵树全局最优

• 单棵树的泛化能力有限:这也是随机森林、梯度提升树等集成方法出现的重要原因

📘 小结

决策树通过不断划分样本空间,学习一组“如果……那么……”的规则来完成分类或回归。它直观、可解释,是理解规则学习、模型复杂度与过拟合问题的重要入口。

“点赞有美意,赞赏是鼓励”

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询