【机器学习|DAY06】决策树(Decision Tree)笔记
决策树
1. 决策树概述
决策树是一种监督学习算法,既能做分类也能做回归,实践中更多用于分类。
核心思想:用树状结构模拟我们做决策时的 if-else 逻辑。
- 非叶子节点:一个判断条件,比如“年龄 > 30 岁?”
- 分支:该节点判断的结果,比如“年龄<=30”或“年龄>30”
- 叶子节点:最终决策结果,比如“见”或“不见”

一棵训练好的决策树,就是由数据自主总结出的一整套“如果…那么…”规则。给一个新样本,从根节点出发,一路按照条件判断往下走,走到某个叶子就得到了预测值。
为什么要学决策树? [具体的对比在第八小节]
- 之前学过线性回归和逻辑回归,它们的核心假设是特征和目标之间存在线性关系。决策树不预设数据的分布形式,靠的是对特征空间反复切分,能捕捉非线性关系。
- 另一个关键优势是可解释性。可以把整棵树画出来,向非技术人员逐条解释"这个客户为什么被拒了",顺着路径把每个判断条件念一遍就清清楚楚。这在金融风控、医疗诊断等需要解释决策理由的场景里极其重要。
关于"树"和之前学的"线性方程"的对应关系:在线性回归中,模型学到的"知识"是权重 w 和偏置 b;在决策树中,模型学到的"知识"就是这棵树的结构,包括每个节点选哪个特征、切分点在哪、叶子对应什么结果。两者的学习逻辑是一致的,只是表达"知识"的形式不同。
2. 工作流程
和线性回归一样,决策树也有清晰的训练 — 预测两阶段,但两者“学到的模型”完全不一样:线性回归学到的是一组权重 (w) 和偏置 (b),而决策树学到的是一棵由特征判断构成的分支树。
训练阶段(核心:让机器自己总结规律)
- 接收训练数据:给定包含 m 个样本的训练集,每个样本有 n 个特征 X₁, X₂, …, Xₙ,以及对应的真实标签 y。
- 从根节点开始,逐层选择划分特征:
- 遍历每个可用特征,评估"如果按这个特征划分,数据的纯度能提升多少"。
- "纯度提升"由划分依据来量化。分类问题用信息增益、信息增益率或基尼指数;回归问题用均方误差(MSE)。
- 选纯度提升最大的那个特征作为当前节点的划分条件。
- 递归生成子树:按选中特征的取值将数据分到各子节点,对每个子节点重复步骤 2。
- 停止条件(满足任一即停止生长):
- 当前节点内所有样本类别一致,也就是已经纯到极致,不必再分。
- 没有剩余特征可用,分无可分。
- 节点内样本数少于预设阈值,样本太少,再分不可靠。
- 树的深度达到预设上限,防止长得太深。
- 生成叶子节点:停止时,将当前节点标记为叶子。分类问题取该节点中样本最多的类别作为预测结果;回归问题取样本目标值的均值。
整个训练过程本质上是一个贪心搜索:每一步都选当前看起来最优的切法,但不保证全局最优。这个贪心特性是决策树容易过拟合的根源,太擅长"记住"训练数据的每一条细节了。
这里有一个值得先点明的问题:决策树有没有"损失函数"?
严格来说,决策树在训练时不像线性回归那样定义一个全局的损失函数然后用梯度下降去优化。它用的是划分依据(熵、基尼等)来在每一步局部选择最佳划分。
这个划分依据起到的作用和损失函数很类似:都是用一个数值来量化"当前模型有多好",然后目标是朝着让这个数值更优的方向去调整。
两者也是采用不同的优化方法,在线性回归中,优化方法靠梯度下降逐步减少损失;在决策树中,"优化"靠的是在每一步递归地对数据做最优切分,也就是贪心优化。
两者只是"优化方式"不同,底层的"需要一个标尺来衡量好坏"的思路完全一致。另外,后面要讲的剪枝,在控制模型复杂度方面的作用,和线性模型中的正则化几乎也是同一个角色。可以类比学习,有助于总结对比。
预测阶段
- 接收新样本:拿到一条待预测的特征向量。
- 从根节点开始走树:根据每个节点的判断条件,顺着对应分支进入下一层。
- 到达叶子节点:叶子上标记的类别(分类)或数值(回归)就是预测结果。
预测阶段的时间复杂度是 O(树深度),速度很快。
3. 分类决策树
怎么量化"划分得好不好"?划分依据到底是什么? 三种经典的决策树算法 ID3、C4.5、CART 分别给出了三种答案,对应信息增益、信息增益率和基尼指数。要理解这三个指标,必须先理解信息熵。
3.1 熵类基础概念
3.1.1 信息熵
是什么:熵(Entropy)是衡量一组数据"混乱程度"的指标。
直观理解:
- 如果节点里全是同一类(纯度最高),熵 = 0,不确定性最小。
- 如果各类样本均匀混合(纯度最低),熵达到最大值,不确定性最大。
可以把它想象成“混乱指数”:东西越乱,熵越高。
数学定义:数据集 D 包含 K 个类别,第 k 类样本比例为 pₖ,则 D 的熵为:
H ( D ) = − ∑ k = 1 K p k log 2 ( p k ) H(D) = -\sum_{k=1}^{K} p_k \log_2(p_k) H(D)=−k=1∑Kpklog2(pk)
其中 p k p_k pk 是第 k k k 类样本所占的比例, K K K是类别总数。
决策树的目标就是让每次划分后,各子节点的熵尽可能低,也就是让数据一步步从"混乱"走向"纯净"。比如刚开始的时候是全部数据什么数据都有,熵肯定大,通过不断选择“最能降低混乱”的特征来切分数据,让子节点越来越纯。
3.1.2 条件熵
是什么:按特征 A 把数据 D 划分成若干份后,我们可以计算出划分后的期望熵,即条件熵。
数学定义:这里的结构本质上就是全概率公式,先按特征 A A A 的不同取值将数据分成若干子集 D v D_v Dv,分别计算每个子集的熵,再按子集大小加权求和。条件熵越小,说明用 A A A 划分后数据的纯度越高。
H ( D ∣ A ) = ∑ v ∈ V a l u e s ( A ) ∣ D v ∣ ∣ D ∣ ⋅ H ( D v ) H(D|A) = \sum_{v \in Values(A)} \frac{|D_v|}{|D|} \cdot H(D_v) H(D∣A)=v∈Values(A)∑∣D∣∣Dv∣⋅H(Dv)
其中 Dᵥ 是特征 A 取值为 v 的那些样本。
和信息熵的关系:两者本质上是同一种计算模式,“按比例加权求熵”。信息熵 H(D) 是按目标类别的比例来分组的(或者说根本还没分组,对着整个数据集算熵);条件熵 H(D|A) 是按特征 A 的取值比例来分组,每组算一次熵再加权。可以类比全概率公式的思路来理解:把"知道 A 后数据还乱不乱"拆成"在 A 的每种取值下,子集乱不乱"的加权平均。
3.1.3 特征熵
为了解决 ID3 的偏好问题,C4.5 引入了特征熵(也叫分裂信息量,Split Information)。
是什么:不看目标类别,只看特征自身的分布有多"散"。取值越多、特征熵越大。
数学定义:
H
A
(
D
)
=
−
∑
v
∈
V
a
l
u
e
s
(
A
)
∣
D
v
∣
∣
D
∣
log
2
(
∣
D
v
∣
∣
D
∣
)
H_A(D) = -\sum_{v \in Values(A)} \frac{|D_v|}{|D|} \log_2\left(\frac{|D_v|}{|D|}\right)
HA(D)=−v∈Values(A)∑∣D∣∣Dv∣log2(∣D∣∣Dv∣)
注意和信息熵以及条件熵的区别:信息熵和条件熵用的是目标类别的比例 pₖ,特征熵用的是特征取值的比例 |Dᵥ|/|D|。
熵是用来衡量“纯度”的,但关键在于,你想知道谁“纯不纯”。
- 信息熵和条件熵:想知道的是分类结果纯不纯。所以代入公式的是目标类别的比例 p k p_k pk。
- 特征熵:想知道的是这个特征本身的取值纯不纯。所以代入公式的是特征取值的样本占比 ∣ D v ∣ / ∣ D ∣ |D_v|/|D| ∣Dv∣/∣D∣。
总结:
两类熵公式形式完全一样,但“称量的对象”不同,信息熵/条件熵称的是标签的混乱程度,特征熵称的是特征取值的一致程度。决策树真正用来选分裂特征的是信息增益,它等于:划分前的标签混乱度,减去按照某个特征划分后各子节点标签混乱度的加权和(也就是信息熵-条件熵)。特征熵本身的“纯”只是个中性属性,不是越纯越好。分支太多不是好事,我们需要的是"既提纯又不过分切碎"的划分。
举个例子:
- "性别"的特征熵:男 8/15,女 7/15 → H ≈ 0.9968(取值少,熵较小)
- "客户ID"的特征熵:每种 ID 各 1/15 → H = log₂(15) ≈ 3.91(取值多又均匀,熵很大)
特征熵越大,意味着这个特征把数据切得越"碎"。
3.2 信息增益( ID3 )
数学定义:信息增益 = 信息熵 - 条件熵:
g ( D , A ) = H ( D ) − H ( D ∣ A ) g(D, A) = H(D) - H(D|A) g(D,A)=H(D)−H(D∣A)
含义:用特征 A 划分后,数据的不确定性减少了多少。减少得越多,说明 A 的"划分能力"越强。ID3 算法(Iterative Dichotomiser 3,迭代二分器第 3 版)的核心思想就是在每个节点选信息增益最大的特征来划分。
示例:


缺点:信息增益有一个天然的偏好 - 倾向于选取值数量多的特征。
假设数据集中有一个"客户 ID"特征,每个样本的 ID 都不同(15 个取值)。按 ID 划分,每个子节点只有 1 个样本,熵直接归零,信息增益达到理论最大值,但这棵树毫无泛化能力,它以为"ID=001 → 流失,ID=002 → 不流失"就是规律,实际上完全是在背答案。更可怕的是,哪怕"客户 ID"和预测目标完全没有关系(纯噪声),信息增益仍然会把它排在第一位。
根本原因在于:信息增益只看"提纯效果有多大",不考虑"付出的代价有多大"。也就是说,原因在于信息增益只要求子节点纯度越高越好,却没有惩罚那些分的叉太多的特征。
3.3 信息增益率( C4.5 )
为了平衡信息增益对多值特征的偏爱,C4.5 算法引入信息增益率。
数学定义:把信息增益除以特征熵,就得到了信息增益率(Gain Ratio):
g R ( D , A ) = g ( D , A ) H A ( D ) g_R(D, A) = \frac{g(D, A)}{H_A(D)} gR(D,A)=HA(D)g(D,A)
为什么有效:我们之前介绍到了特征熵看特征自身的分布有多"散",特征熵越大,意味着这个特征把数据切得越"碎"。所以在这个公式里面分子(信息增益)负责衡量提纯能力,分母(特征熵)负责惩罚分支过多。如果一个特征取值极多(如客户 ID),虽然分子很大,但分母同样巨大,除完之后就被拉低了。只有"信息增益确实高,且特征熵不算大"的特征才能脱颖而出。
换句话说,可以这样理解这两项的分工:
- 信息增益 → 控制提纯效果:叶子节点的熵是否足够低,数据是否变纯了。
- 特征熵 → 控制分支数量:树的宽度是否合理,有没有切得太碎。
两者配合,既保证划分有效,又抑制树的过度生长。
示例:

C4.5 的实际做法:并不是简单地直接选信息增益率最大的特征。它会先从所有候选特征中筛出信息增益高于平均水平的那些,再从这些"增益不错的"里面挑选信息增益率最高的。这样避免了分子接近零但分母更小、导致比值反而偏大的极端情况。
3.4 基尼值与基尼指数(CART 算法)
CART(Classification And Regression Tree,分类与回归树)走了另一条路,用基尼值替代熵,避免了 log 运算,计算更快。
3.4.1 基尼值(Gini)
是什么:从数据集 D 中随机抽取两个样本,它们类别标记不一致的概率。基尼值越小,纯度越高。
公式推导:随机抽两个样本,类别一致的概率是 Σ pₖ²(先抽到第 k 类的概率是 pₖ,再抽到同一类的概率也是 pₖ)。用 1 减去"一致"的概率,得到的就是"不一致"的概率:
G i n i ( D ) = 1 − ∑ k = 1 K p k 2 Gini(D) = 1 - \sum_{k=1}^{K} p_k^2 Gini(D)=1−k=1∑Kpk2
以二分类为例,设正例比例为 p:
G i n i ( D ) = 1 − p 2 − ( 1 − p ) 2 = 1 − p 2 − 1 + 2 p − p 2 = 2 p ( 1 − p ) Gini(D) = 1 - p^2 - (1-p)^2 = 1 - p^2 - 1 + 2p - p^2 = 2p(1-p) Gini(D)=1−p2−(1−p)2=1−p2−1+2p−p2=2p(1−p)
- p = 0.5(正负各半):Gini = 2 × 0.5 × 0.5 = 0.5(最不纯)
- p = 1 或 p = 0(全正或全负):Gini = 0(最纯)
基尼值的取值范围是 [0, 0.5](注意比熵的范围 [0, 1] 小一半),但走势完全一致,都是在 0.5 处取最大值。在实际的划分选择中,基尼值和熵极少出现分歧(几乎不会出现一个指标说选特征 A、另一个说选特征 B 的情况),所以这是一个以速度换精度的合理取舍。
3.4.2 基尼指数(Gini Index)
对特征 A 划分后的各子集,按比例加权求基尼值:
G i n i _ i n d e x ( D , A ) = ∑ v ∈ V a l u e s ( A ) ∣ D v ∣ ∣ D ∣ ⋅ G i n i ( D v ) Gini\_index(D, A) = \sum_{v \in Values(A)} \frac{|D_v|}{|D|} \cdot Gini(D_v) Gini_index(D,A)=v∈Values(A)∑∣D∣∣Dv∣⋅Gini(Dv)
基尼指数越小,划分效果越好。CART 每次选基尼指数最小的特征来划分。
3.4.3 CART 的两大特性
特性一:一定是二叉树。 即使特征有多个取值(比如"年龄段"有三个值:≤30、31-45、>45),CART 也不会一次分出三个子节点,而是从中找一个最优的二分方式。比如可能的二分组合有:
- {≤30} vs {31-45, >45}
- {31-45} vs {≤30, >45}
- {>45} vs {≤30, 31-45}
CART 会逐一计算每种二分方式下的基尼指数,选最小的那个。对于一个有 m 个取值的特征,可能的二分组合有 2^(m-1) - 1 种。
特性二:天然支持连续值。 对于连续特征(比如实际年龄 23、25、28……),怎么找分界点?做法是:
- 把该特征的所有取值从小到大排序。
- 逐一考察每两个相邻值之间的中点作为候选分界点。
- 每个候选点把数据分成"≤该值"和">该值"两组,计算基尼指数。
- 选基尼指数最小的那个中点。
例如:
年龄排序:22, 25, 28, 31, 35, 40, 45
候选分界点:23.5, 26.5, 29.5, 33, 37.5, 42.5
对每个候选点都算一次基尼指数,取最优。
这里有一个细节:既然 CART 是二叉树而 ID3/C4.5 是多叉树,那 ID3/C4.5 不能直接处理连续值(连续值的取值太多)。C4.5 后来也补充了连续值处理逻辑,做法和 CART 类似,用二分法把连续值离散化,但这不是它原生的能力。
换句话说,遇到多叉问题时,CART 会将多叉强行拆成一系列二叉问题,从而保证树的统一性并简化计算。
示例:

3.5 三种划分依据对比
| 维度 | ID3 | C4.5 | CART |
|---|---|---|---|
| 划分指标 | 信息增益 | 信息增益率 | 基尼指数 |
| 树结构 | 多叉树 | 多叉树 | 二叉树 |
| 连续值处理 | 不支持 | 支持(二分法) | 支持(天然二分) |
| 缺失值处理 | 不支持 | 支持 | 支持 |
| 偏好 | 偏好取值多的特征 | 偏好取值少但增益高的 | 无显著偏好 |
| 计算效率 | 较低(有 log) | 较低(有 log) | 较高(无 log) |
| 能做回归 | 否 | 否 | 是 |
选型建议:ID3 已基本被 C4.5 和 CART 替代,现在更多作为理论基础。需要直观的多叉树结构且数据都是离散值 → C4.5。追求效率、要做回归、或使用 sklearn(底层就是 CART 的优化版)→ CART。
补充了解缺失值的处理:
算法 能否原生处理缺失值 缺失值处理核心机制 为什么能 / 不能 关键备注 ID3 ❌ 不能 无 信息增益计算依赖样本特征值完整,没有缺失样本的归属规则,也无法计算含缺失的熵。 历史上最早的决策树算法,只能丢弃缺失样本。 C4.5 ✅ 能 概率权重分配 ① 计算增益时只使用无缺失样本,再按无缺失比例缩放增益;
② 分裂时将缺失样本按各分支样本量比例加权分配到所有子节点;
③ 预测时同样按权重走多条路径,融合结果。与“信息增益率”(多一个除法)是独立的两套设计:增益率解决多值偏好,权重分配解决缺失值。 CART ✅ 能 代理分裂 ① 训练时只从无缺失样本找最佳分裂点;
② 从其他特征中找出与主分裂最像的代理变量;
③ 预测时若主分裂变量缺失,依序用代理变量决定走向,全缺则走默认分支。代理变量要求特征间有一定相关性,否则失效(变成全走默认分支)。 逻辑回归 ❌ 不能(原生) 无(依赖外部填补) 模型本质是线性组合 ( \beta_0 + \sum \beta_j x_j ),缺失导致线性项无法计算,似然函数和梯度无法定义。标准求解器遇缺失即报错。 补救需在模型外做多重插补、EM算法等预处理,但非算法自带。
4. 回归决策树
决策树不只做分类,也能做回归(预测连续值)。回归树同样采用二分递归划分,只不过评判标准不再是熵或基尼,而是预测误差。
4.1 回归树的划分依据
分类树的划分依据是熵或基尼值,目标是让子节点的"类别更纯"。回归树的目标值 y 是连续值,不存在"纯度"的概念,但存在一个对应的直觉:划分之后,各子节点内样本的目标值应该尽量接近,也就是组内差异小。
最常用的量化方式是均方误差 MSE:
M S E ( D ) = 1 ∣ D ∣ ∑ i ∈ D ( y i − y ˉ D ) 2 MSE(D) = \frac{1}{|D|} \sum_{i \in D} (y_i - \bar{y}_D)^2 MSE(D)=∣D∣1i∈D∑(yi−yˉD)2
其中 y ˉ D ȳ_D yˉD 是子集 D 中所有样本目标值的均值。
对于一次二分(CART 回归树也是二叉树),分别计算左子节点和右子节点的 MSE,按样本数加权:
L o s s = ∣ D 左 ∣ ∣ D ∣ ⋅ M S E ( D 左 ) + ∣ D 右 ∣ ∣ D ∣ ⋅ M S E ( D 右 ) Loss = \frac{|D_{左}|}{|D|} \cdot MSE(D_{左}) + \frac{|D_{右}|}{|D|} \cdot MSE(D_{右}) Loss=∣D∣∣D左∣⋅MSE(D左)+∣D∣∣D右∣⋅MSE(D右)
选使这个加权 Loss 最小的特征和分界点。本质上和分类树的逻辑一模一样:分类要"类别更纯",回归要"数值更集中"。
示例:

4.2 回归树的预测
新样本走到叶子节点后,输出的是该叶子节点所有训练样本目标值的均值。
4.3 分类树 vs 回归树
| 维度 | 分类树 | 回归树 |
|---|---|---|
| 预测目标 | 离散类别 | 连续数值 |
| 划分依据 | 熵 / 基尼指数 | MSE / MAE |
| 叶子输出 | 多数类别 | 样本均值 |
| 评价指标 | 准确率、召回率等 | MSE、R²、MAE 等 |
| predict_proba | 有(各类概率) | 无 |
5. 剪枝
决策树有一个天生的毛病:如果不加任何约束,它会一直分下去,直到每个叶子节点只有一个样本(或所有样本同类)。此时训练集准确率可以到 100%,但泛化能力极差,树把训练数据中的噪声和偶然波动也当成"规律"记下来了,这就是过拟合。
简单来说:决策树如果任其生长,会记住训练数据中的每一个噪声和特异点,导致过拟合。
剪枝(Pruning)就是通过削减一些不必要的分支来抑制过拟合。
在线性回归中,正则化通过限制权重 w 的大小来防止模型太复杂;在决策树中,剪枝通过砍掉不可靠的分支来降低复杂度。两者的目标完全一致,提高泛化能力。
剪枝有两种策略:预剪枝和后剪枝。
5.1 预剪枝(Pre-pruning)
是什么:在树生长的过程中,每准备划分一个节点之前,先问一句"这次划分真的有用吗?"。如果划分带来的提升不够大,就直接停止,把当前节点标为叶子。
预剪枝的完整过程
利用验证集进行评估(不能再用训练集,否则模型会自欺欺人):
假设当前节点中有 10 个训练样本,如果不划分,就直接将该节点标记为训练样本中最多的类别(比如“正类”)。然后我们用验证集去测试:以该节点为叶子的模型在验证集上的准确率是多少。接着,我们尝试用某个特征划分,生成子节点,再用验证集测试此时模型的准确率。如果划分后验证集准确率反而下降,说明这次划分对泛化无益,应该停止,并将该节点直接标为多数类。
例子:当前节点训练样本有 6 个正类、4 个负类,若不划分,叶节点预测为正类。验证集上有 20 个样本,预测全为正,准确率 60%。若根据“收入”划分成两个子节点,验证集准确率变为 58%。那么预剪枝就会取消这次划分,避免过拟合。
这个判断会在树生长的每个节点都做一遍。本质上是一种**"早停(early stopping)"策略**。
优点:训练快,内存和预测开销都低。
缺点:贪心导致的"短视",从当前节点看这次划分似乎没啥用,但如果继续往下细分,可能后续的分叉能带来显著收益。预剪枝容易因为过早终止而欠拟合。
5.2 后剪枝(Post-pruning)
是什么:先让树不加限制地充分生长,长成一棵完整的大树(可能很深很复杂),然后从下往上,检查每个非叶子节点,问"把这个节点变成叶子,会怎样?"。
后剪枝的完整过程
- 在训练集上生成一棵完整的决策树,不设任何停止条件(让树长到最大)。
- 自底向上遍历每一个非叶子节点(从最靠近叶子的节点开始):
- 将该节点及其下面的所有子树替换成一片叶子,叶子类别取该节点覆盖的训练样本中数量最多的类别。
- 在验证集上比较剪枝前和剪枝后的准确率。
- 如果剪枝后准确率没有下降(甚至更高),就永久剪掉这个分支;如果准确率下降,就恢复原样,保留这个分支。
- 重复直到遍历完所有节点,直到没有任何一个节点可以被剪掉。
优点: 在完整树的基础上做减法,不容易欠拟合。通常泛化能力比预剪枝更好。不会出现"砍早了"的问题。
缺点:先生成大树再逐一修剪,训练开销比预剪枝大很多。树的规模最终也可能比预剪枝的大。
5.3 预剪枝 vs 后剪枝
| 维度 | 预剪枝 | 后剪枝 |
|---|---|---|
| 策略 | 边生长边抑制 | 先长完再修剪 |
| 时机 | 训练过程中 | 训练完成后 |
| 训练开销 | 小(省了不必要的枝) | 大(先生成大树再逐一验证) |
| 欠拟合风险 | 较高(可能砍早了) | 较低 |
| 泛化能力 | 一般 | 通常更好 |
sklearn 的决策树默认使用预剪枝策略(通过 max_depth、min_samples_split 等参数控制)。后剪枝通过代价复杂度剪枝(CCP)来实现。
预剪枝常用停止条件:
- 节点中的样本数小于预设的最小值
min_samples_split - 叶子节点样本数小于
min_samples_leaf - 树达到最大深度
max_depth - 划分带来的纯度提升(或误差下降)小于阈值
min_impurity_decrease
6. API 详解
sklearn 中的决策树都在 sklearn.tree 模块下,主要用到两个类:
DecisionTreeClassifier:分类树DecisionTreeRegressor:回归树
6.1 分类树:DecisionTreeClassifier
from sklearn.tree import DecisionTreeClassifier
# 创建模型(所有参数都有默认值,不传就用默认)
model = DecisionTreeClassifier(
criterion='gini', # 划分依据:'gini'(默认) 或 'entropy'(熵)
max_depth=None, # 树的最大深度,None 表示不限制
min_samples_split=2, # 节点至少有多少样本才继续划分
min_samples_leaf=1, # 叶子节点至少有多少样本
max_features=None, # 每次划分最多考虑几个特征
random_state=42, # 随机种子,保证结果可复现
ccp_alpha=0.0, # 代价复杂度剪枝参数
class_weight=None # 类别权重,样本不均衡时很重要
)
# 训练
model.fit(X_train, y_train)
# 预测
y_pred = model.predict(X_test) # 输出类别标签
y_proba = model.predict_proba(X_test) # 输出每类的概率
y_log_proba = model.predict_log_proba(X_test) # 对数概率
# 评估
score = model.score(X_test, y_test) # 返回准确率
关键参数详解
| 参数 | 类型/默认值 | 含义 | 使用建议 |
|---|---|---|---|
criterion | 'gini'(默认)或 'entropy' | 划分依据,'gini'=基尼指数,'entropy'=信息增益(熵) | 两者实际效果差异很小,gini 计算稍快。都可以试试,选验证集上表现好的。 |
max_depth | int,默认 None(不限) | 树的最大深度 | 最重要的预剪枝参数。数据量小设 3~5,数据量大设 5~15。优先调这个。 |
min_samples_split | int/float,默认 2 | 节点最少样本数,少于这个数就不再划分 | 增大可以防止在样本极少时还强行划分。设为整数表示绝对数量,设为浮点数(如 0.05)表示比例。 |
min_samples_leaf | int/float,默认 1 | 叶子节点最少样本数 | 和上面类似但作用于叶子层。设为 5 意味着每个叶子至少要有 5 个样本。配合 max_depth 一起调。 |
max_features | int/float/str,默认 None(全用) | 每次划分时随机考虑的特征数 | 设为 'sqrt' 或 'log2' 增加随机性,主要在随机森林中有用。单棵树一般不调。 |
random_state | int,默认 None | 随机种子 | 养成设一个固定值(如 42)的习惯,方便复现结果。 |
ccp_alpha | float,默认 0.0 | 代价复杂度剪枝的 α | 0=不做 CCP。用交叉验证(如 model.cost_complexity_pruning_path)来选最优值,增大得到更小的树。 |
class_weight | dict/'balanced'/None | 类别权重 | 样本不均衡时设为 'balanced',自动按类别样本比例分配权重,少数类获得更大权重。 |
6.2 回归树:DecisionTreeRegressor
API 和分类树高度一致,区别集中在几个参数的默认值和输出:
from sklearn.tree import DecisionTreeRegressor
model = DecisionTreeRegressor(
criterion='squared_error', # 'squared_error'(MSE), 'absolute_error'(MAE),
# 'friedman_mse', 'poisson'
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
max_features=None,
random_state=42,
ccp_alpha=0.0
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test) # 输出连续值
score = model.score(X_test, y_test) # 返回 R²(决定系数),不是准确率
6.3 回归树 vs 分类树
| 维度 | DecisionTreeClassifier | DecisionTreeRegressor |
|---|---|---|
criterion | 'gini'(默认)/ 'entropy' | 'squared_error'(默认)/ 'absolute_error' / 'friedman_mse' / 'poisson' |
预测输出 predict() | 类别标签 | 连续数值 |
predict_proba() | 有(每个类别的概率) | 无 |
score() 返回值 | 准确率(accuracy) | R²(决定系数) |
6.4 模型可视化
from sklearn.tree import plot_tree, export_text
import matplotlib.pyplot as plt
# 图形化展示
plt.figure(figsize=(20, 10))
plot_tree(
model,
filled=True, # 节点按类别着色,颜色越深纯度越高
feature_names=feature_names, # 特征名列表
class_names=class_names, # 类别名列表
rounded=True, # 圆角节点
proportion=True # 显示比例而非绝对数量
)
plt.show()
# 文本形式输出(不需要 matplotlib)
print(export_text(model, feature_names=feature_names))
7. 决策树 vs 逻辑回归
把上面的分析浓缩成一张表,每个差异都带上了原因。
| 维度 | 逻辑回归 | 决策树 | 为什么会有这个差异 |
|---|---|---|---|
| 决策边界 | 一条超平面(平滑、全局一致) | 轴平行的阶梯状折线(分段常数) | 逻辑回归每次同时用所有特征的线性组合判断;决策树每次只切一个特征,边界只能垂直于那个特征的轴 |
| 模型类型 | 参数化(n+1 个固定参数) | 非参数化(结构随数据增长) | 逻辑回归的模型形式 P=sigmoid(w·x+b) 在训练前已确定;决策树的结构由贪心递归逐层长出,没有预设的参数量 |
| 优化方式 | 最小化全局交叉熵损失,梯度下降连续优化 | 贪心递归分割,每步选最优切分点,离散、不可逆 | 逻辑回归的参数是连续的 w,可求导;决策树要优化树拓扑结构,是离散组合问题,NP-hard,只能贪心 |
| 特征缩放 | 必须做:梯度 ∂J/∂wⱼ ∝ xⱼ,量纲差距直接转为梯度差距 | 不需要:只做 xⱼ ≤ t 的比较,排序在缩放前后不变 | 梯度依赖数值大小 → 缩放敏感;比较依赖数值顺序 → 缩放无关 |
| 非线性能力 | 差:除非手动构造多项式/交互特征 | 强:逐层切分天然逼近任意形状 | 线性组合本质上是单调的;树的规则组合可以是任意条件嵌套 |
| 交互效应 | 需手动构造 x₁×x₂ 等交叉项 | 天然支持:路径上多条件自动构成 AND | 各特征独立乘 w 后求和,互不"对话";树的层级结构让条件自然叠加 |
| 稳定性 | 稳定:增删样本只微调 w | 不稳定:一个样本可颠覆整棵树 | 连续参数对单样本扰动不敏感;贪心离散选择对根节点数据变化极敏感 |
| 可解释方向 | “哪个因素重要、方向如何”(看 w) | “为什么是这个结果”(念规则路径) | 参数有统计含义;路径天然是自然语言 |
可以从三维度总结记忆 - 决策树在特征处理、非线性和可解释性上的优势与局限。
以上为个人学习总结,旨在梳理个人理解。如有疏漏或不当之处,欢迎指正与交流。如果文章对你有帮助,别忘了点个赞、留个言,让更多的小伙伴看到~ 我们下篇再见!
更多推荐
所有评论(0)