1. 决策树介绍
决策树算法:
是非参数学习算法
可以解决分类(多分类)问题
可以解决回归问题:落在叶子节点的数据的平均值作为回归的结果
构建决策树的三个步骤:
特征选择:选取有较强分类能力的特征
决策树生成
决策树剪枝
2. ID3 决策树
ID3 树是基于信息增益构建的决策树.
2.1 信息熵
- 熵在信息论中代表随机变量不确定度的度量。
- 熵越大,数据的不确定性度越高
- 熵越小,数据的不确定性越低
2.2 信息增益
特征 A A A对训练数据集D的信息增益 g ( D , A ) g(D,A) g(D,A),定义为集合 D D D的经验熵 H ( D ) H(D) H(D)与特征A给定条件下D的经验熵 H ( D ∣ A ) H(D|A) H(D∣A)之差。即
g ( D , A ) = H ( D ) − H ( D ∣ A ) \large g(D,A)=H(D)-H(D|A) g(D,A)=H(D)−H(D∣A)
根据信息增益选择特征方法是:对训练数据集D,计算其每个特征的信息增益,并比较它们的大小,并选择信息增益最大的特征进行划分。表示由于特征 A A A而使得对数据D的分类不确定性减少的程度。
2.3 ID3算法步骤
- 计算每个特征的信息增益
- 使用信息增益最大的特征将数据集 S 拆分为子集
- 使用该特征(信息增益最大的特征)作为决策树的一个节点
- 使用剩余特征对子集重复上述(1,2,3)过程
3. C4.5 决策树
3.1 信息增益率计算公式
- Gain_Ratio 表示信息增益率
- IV 表示分裂信息、内在信息
- 特征的信息增益 ➗ 内在信息
- 如果某个特征的特征值种类较多,则其内在信息值就越大。即:特征值种类越多,除以的系数就越大。
- 如果某个特征的特征值种类较小,则其内在信息值就越小。即:特征值种类越小,除以的系数就越小。
信息增益比本质: 是在信息增益的基础之上乘上一个惩罚参数。特征个数较多时,惩罚参数较小;特征个数较少时,惩罚参数较大。惩罚参数:数据集D以特征A作为随机变量的熵的倒数。
3.2 ID3和C4.5对比
-
ID3算法缺点
- ID3算法不能处理具有连续值的属性
- ID3算法不能处理属性具有缺失值的样本
- 算法会生成很深的树,容易产生过拟合现象
- 算法一般会优先选择有较多属性值的特征,因为属性值多的特征会有相对较大的信息增益,但这里的属性并不一定是最优的
-
C4.5算法的核心思想是ID3算法,对ID3算法进行了相应的改进。
- C4.5使用的是信息增益比来选择特征,克服了ID3的不足。
- 可以处理离散型描述属性,也可以处理连续数值型属性
- 能处理不完整数据
-
C4.5算法优缺点
- 优点:分类规则利于理解,准确率高
- 缺点
- 在构造过程中,需要对数据集进行多次的顺序扫描和排序,导致算法的低效
- C4.5只适合于能够驻留内存的数据集,当数据集非常大时,程序无法运行
-
无论是ID3还是C4.5最好在小数据集上使用,当特征取值很多时最好使用C4.5算法。
4. CART 分类决策树
4.1 Cart树简介
Cart模型是一种决策树模型,它即可以用于分类,也可以用于回归,其学习算法分为下面两步:
(1)决策树生成:用训练数据生成决策树,生成树尽可能大
(2)决策树剪枝:基于损失函数最小化的剪枝,用验证数据对生成的数据进行剪枝。
分类和回归树模型采用不同的最优化策略。Cart回归树使用平方误差最小化策略,Cart分类生成树采用的基尼指数最小化策略。
Scikit-learn中有两类决策树,他们均采用优化的Cart决策树算法。一个是DecisionTreeClassifier一个是DecisionTreeRegressor回归。
4.2 基尼指数计算公式
-
信息增益(ID3)、信息增益率值越大(C4.5),则说明优先选择该特征。
-
基尼指数值越小(cart),则说明优先选择该特征。
4.3 CART树生成
输入:数据集 D D D ,特征 A A A ,样本个数阈值、基尼系数阈值
输出: C A R T CART CART决策树 T T T
(1)对于当前节点的数据集为 D D D,如果样本个数小于阈值或者没有特征,则返回决策子树,当前节点停止递归;
(2)计算样本集 D D D的基尼系数,如果基尼系数小于阈值,则返回决策树子树,当前节点停止递归;
(3)计算当前节点现有的各个特征的各个特征值对数据集 D D D的基尼系数;
(4)在计算出来的各个特征的各个特征值对数据集 D D D的基尼系数中,选择基尼系数最小的特征 A A A和对应的特征值 α \alpha α。根据这个最优特征和最优特征值,把数据集划分成两部分 D 1 D_1 D1和, D 2 D_2 D2同时建立当前节点的左右节点,左节点的数据集 D D D为 D 1 D_1 D1,右节点的数据集 D D D为 D 2 D2 D2;
(5)对左右的子节点递归的调用前面1-4步,生成决策树。
4.4 CART树剪枝
我们知道,决策树算法对训练集很容易过拟合,导致泛化能力很差,为解决此问题,需要对CART树进行剪枝。CART剪枝算法从“完全生长”的决策树的底端剪去一些子树,使决策树变小,从而能够对未知数据有更准确的预测,也就是说CART使用的是后剪枝法。一般分为两步:先生成决策树,产生所有可能的剪枝后的CART树,然后使用交叉验证来检验各种剪枝的效果,最后选择泛化能力好的剪枝策略。
5. Cart回归决策树
CART 回归树和 CART 分类树的不同之处在于:
- CART 分类树预测输出的是一个离散值,CART 回归树预测输出的是一个连续值。
- CART 分类树使用基尼指数作为划分、构建树的依据,CART 回归树使用平方损失。
- 分类树使用叶子节点里出现更多次数的类别作为预测类别,回归树则采用叶子节点里均值作为预测输出
CART 回归树构建:
Loss ( y , f ( x ) ) = ( f ( x ) − y ) 2 \operatorname{Loss}(y, f(x))=(f(x)-y)^{2} Loss(y,f(x))=(f(x)−y)2
CART 回归树构建过程如下:
- 选择第一个特征,将该特征的值进行排序,取相邻点计算均值作为待划分点
- 根据所有划分点,将数据集分成两部分:R1、R2
- R1 和 R2 两部分的平方损失相加作为该切分点平方损失
- 取最小的平方损失的划分点,作为当前特征的划分点
- 以此计算其他特征的最优划分点、以及该划分点对应的损失值
- 在所有的特征的划分点中,选择出最小平方损失的划分点,作为当前树的分裂点
回归决策树是二叉树
6. 剪枝
6.1 什么是剪枝?
剪枝 (pruning)是决策树学习算法对付 过拟合 的主要手段。
在决策树学习中,为了尽可能正确分类训练样本,结点划分过程将不断重复,有时会造成决策树分支过多,这时就可能因训练样本学得"太好"了,以致于把训练集自身的一些特点当作所有数据都具有的一般性质而导致过拟合。因此,可通过主动去掉一些分支来降低过拟合的风险。
剪枝是指将一颗子树的子节点全部删掉,利用叶子节点替换子树(实质上是后剪枝技术),也可以(假定当前对以root为根的子树进行剪枝)只保留根节点本身而删除所有的叶子,以下图为例:
6.2 为什么要进行树的剪枝?
决策树是充分考虑了所有的数据点而生成的复杂树,有可能出现过拟合的情况,决策树越复杂,过拟合的程度会越高。
考虑极端的情况:如果我们令所有的叶子节点都只含有一个数据点,那么我们能够保证所有的训练数据都能准确分类,但是很有可能得到高的预测误差,原因是将训练数据中所有的噪声数据都”准确划分”了,强化了噪声数据的作用。
而剪枝修剪分裂前后分类误差相差不大的子树,能够降低决策树的复杂度,降低过拟合出现的概率。
6.3 如何剪枝?
预剪枝:预剪枝是指在决策树生成过程中,对每个结点在划分前先进行估计,若当前结点的划分不能带来决策树泛化性能提升,则停止划分并将当前结点标记为叶结点;
后剪枝:则是先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能提升,则将该子树替换为叶结点。
剪枝技术对比
预剪枝优点:
- 预剪枝使决策树的很多分支没有展开,不单降低了过拟合风险,还显著减少了决策树的训练、测试时间开销
预剪枝缺点:
- 有些分支的当前划分虽不能提升泛化性能,甚至会导致泛化性能降低,但在其基础上进行的后续划分却有可能导致性能的显著提高
- 预剪枝决策树也带来了欠拟合的风险
后剪枝优点:
- 比预剪枝保留了更多的分支。一般情况下,后剪枝决策树的欠拟合风险很小,泛化性能往往优于预剪枝
后剪枝缺点:
- 但后剪枝过程是在生成完全决策树之后进行的,并且要自底向上地对树中所有非叶子节点进行逐一考察,因此在训练时间开销比未剪枝的决策树和预剪枝的决策树都要大得多。
7. 可执行示例代码
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor
from sklearn.metrics import accuracy_score, mean_squared_error
import matplotlib.pyplot as plt
from sklearn import tree
# 生成示例数据(分类任务)
np.random.seed(0)
X = np.random.rand(100, 2)
y = (X[:, 0] + X[:, 1] > 1).astype(int)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建决策树分类器
clf = DecisionTreeClassifier(criterion='gini', max_depth=3, min_samples_split=2, min_samples_leaf=1)
# 训练模型
clf.fit(X_train, y_train)
# 预测
y_pred = clf.predict(X_test)
# 评估模型
accuracy = accuracy_score(y_test, y_pred)
print("分类决策树准确率:", accuracy)
# 生成示例数据(回归任务)
X = np.random.rand(100, 1)
y = 4 + 3 * X[:, 0] + np.random.randn(100) * 0.5
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建决策树回归器
reg = DecisionTreeRegressor(max_depth=3, min_samples_split=2, min_samples_leaf=1)
# 训练模型
reg.fit(X_train, y_train)
# 预测
y_pred = reg.predict(X_test)
# 评估模型
mse = mean_squared_error(y_test, y_pred)
print("回归决策树均方误差 (MSE):", mse)
# 可视化决策树
plt.figure(figsize=(12,8))
tree.plot_tree(clf, filled=True)
plt.show()