接上期:
一、理论知识
CART算法是给定输入随机变量X条件下输出随机变量Y的条件概率分布的学习方法。CART假设决策树是二叉树,内部节点取值为“是”或“否”。这样的决策树等价于递归地二分每个特征,将特征空间划分为有限个单元,并在这些单元上确定预测的概率分布即输入给定的条件下输出的条件概率分布。
1.0、特征选择:基尼指数
- 分类树用基尼指数选择最优特征,同时决定该特征的最优二值切分点。
- 分类问题中假设有K个类,样本点属于第k类的概率为,则概率分布的基尼指数为
对于二分类问题,若样本点属于第1个类的概率为p,则概率分布的基尼指数为 - 如果样本集合D根据特征A是否取某一可能值a被分割为和两部分,即,则在特征A的条件下,集合D的基尼指数定义为
基尼指数表示集合D的不确定性,基尼指数表示经分割后集合D的不确定性。基尼系数越大,样本集合的不确定性也越大,这一点与熵相似。
1.1、决策树的生成
-
CART生成算法
- 输入:训练数据集D,停止计算的条件
- 输出: CART决策树
- 计算现有特征对该数据集的基尼指数。根据特征A=a的测试为“是”或“否”,将数据集划分为两个子集,利用上面的公式计算A=a时的基尼指数;
- 在所有可能的特征A以及它们所有可能分割点a中,选择基尼系数最小的特征及其分割点作为最优特征和最优切分点。并根据该特征和切分点,从现节点生成两个子节点,将训练集划分到两个子节点去;
- 对两个子节点递归地调用上述步骤,直至满足停止条件;
- 生成CART决策树。
-
实例:下表为数据集,应用CART算法生成决策树。
-
数据集D关于特征A1的基尼指数:
由于和相等且最小,所以和都可以选择作为的最优切分点。 -
求特征和的基尼指数:
由于特征和的切割点只有一个,所以它们就是最优切分点。 -
求特征的基尼指数:
最小,所以选择作为的最优切分点。 -
在4个特征中,,,,,最小,所以选择特征为最优特征,为最优切分点。于是根节点生成两个子节点,一个是叶节点(的类别输出都是“是”),对另一个节点继续使用以上方法选择最优特征和最优切分点,结果为。以此计算,所得节点都是叶节点。
对于同样的案例,CART算法的决策树结果与ID3的决策树结果一致。
1.2、CART剪枝
下面这张图可以很好的理解分类树越复杂,训练集的精确度越高;但测试集的精确度到达某一高度时会随着树的复杂度增加而减小,即产生过拟合。而剪枝正是为了防止过拟合,缩小树的复杂度而生的。在上期博客中,讲解了预剪枝和后剪枝,这里要讲的是CART算法中CART剪枝。
- 在一个复杂的树内部,有许多较简单的子树,每一个子树代表在模型复杂性和训练集误差分类率之间的一种折中。CART算法把这样一些子树的集合视为候选模型,这些候选子树被应用于验证集,具有最低验证集误分类率的树被选作最终模型。
- CART使用代价复杂度剪枝算法Cost-Complexity Pruning(CCP) (后剪枝算法的一种)。该方法把树的代价复杂度看做树中树叶结点的个数和树的错误率的函数。从树的底部开始,对于每个内部结点N,计算N处的子树的代价复杂度和该子树剪枝后的N处子树(即用一个树叶结点代替)的代价复杂度。比较这两个值,如果剪去结点N的子树导致较小的代价复杂度,则剪去该子树;否则,保留。
- 下图中T树生成的完整决策树,T2为其中的子树,T-T2即为剪切后的决策树,比较T和T-T2的代价复杂度,如果T-T2的代价复杂度有所减小,那么将子树T2剪掉。
- 从整个树 T0 开始,先剪去一棵子树,生成子树 T1,在 T1 上再剪去一棵子树,生成子树 T2,重复这个操作,直到最后只剩下一个根节点的子树 Tn,得到了子树序列 T0~Tn。
- 利用独立的验证数据集,计算每个子树的平方误差(回归树)或者基尼指数(分类树),选择误差最小的那个子树作为最优的剪枝后的树。因为建模的时候,目标就是让损失函数达到最优,那剪枝的时候也用损失函数来评判。对任意子树 T,损失函数如下形式:
其中为误差(例如基尼指数),为子树的叶节点树,为参数,用来权衡训练数据的拟合程度和模型的复杂度。
二、python实战
import numpy as np
from sklearn.tree import DecisionTreeClassifier
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
plt.rcParams['font.sans-serif'] =['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
x = load_iris().data
y = load_iris().target
x_train,x_test,y_train,y_test= train_test_split(x,y,test_size=0.3,random_state=2022)
destree = DecisionTreeClassifier(criterion='gini',splitter='best',max_depth=3,max_leaf_nodes=4) # 选择gini准则即为CART算法 参数max_depth(树的最大深度)和max_leaf_nodes(最大叶节点数) 可以进行剪枝
dd = destree.fit(x_train,y_train)
ytest_pre = destree.predict(x_test)
ytrain_pre = destree.predict(x_train)
print(f'训练集精确度:{accuracy_score(y_train,ytrain_pre)}')
print(f'测试集精确度:{accuracy_score(y_test,ytest_pre)}')
训练集精确度:0.9714285714285714
测试集精确度:0.9777777777777777
plt.figure(figsize=(8,6))
plot_tree(dd)
plt.show()
文章出处登录后可见!
已经登录?立即刷新