【机器学习笔记】——决策树(Decision Tree)
目 录
- 1 决策树
- 1.1 特征选择
- 1.1.1 基础定义
- 1.1.2 最优特征标准
- 1.2 树的生成
- 1.2.1 ID3 算法
- 1.2.2 C4.5 算法
- 1.2.2.1 如果特征是连续的
- 1.2.2.2 如果数据中有缺失值
- 1.2.3 CART 算法
- 1.2.3.1 CART 分类
- 1.2.3.2 CART 回归
- 1.2.4 ID3 Vs C4.5 Vs CART
- 1.3 树的剪枝
- 1.3.1 ID3 & C4.5
- 1.3.1.1 后剪枝 & CCP 原则
- 1.3.1.2 预剪枝 & REP 原则
- 1.3.2 CART(后剪枝 & CCP)
- 1.3.2.1 假设——给定 $\alpha$,一定存在使损失函数最小的子树,且这样的子树唯一
- 1.3.2.2 没搞懂的问题
- 1.3.3 预剪枝 Vs 后剪枝
- 1.3.4 CCP Vs REP Vs PEP
- 1.3.1 ID3 & C4.5
- 1.4 多变量决策树
- 1.5 多输出决策树
- 1.6 C5.0
- 1.7 随机森林
- 1.8 实例
- 1.8.1 决策树分类
- 1.8.1.1 ID3
- 1.8.1.2 C4.5
- 1.8.1.3 CART
- 1.8.2 CART回归
- 1.8.1 决策树分类
- 1.9 总结
- 1.9.1 决策树的优点
- 1.9.2 决策树的缺点
- 1.1 特征选择
- 2 算法实现
- 2.1 基础数据结构的python实现
- 2.2 数据不确定性计算的python实现
- 2.2.1经验熵
- 2.2.2 条件熵
- 2.2.3 信息增益
- 2.2.4 特征的熵
- 2.2.5 信息增益比
- 2.2.6 基尼指数
- 2.3 ID3的python实现
- 3 sklearn分类决策树
- 3.1 参数列表
- 3.2 属性列表
- 3.3 模型调参注意事项:
- 3.4 实例——鸢尾花多分类决策树
- 3.4.1 导入数据
- 3.4.2 决策树可视化
- 3.4.3 交叉验证
- 3.4.4 调参
- 3.4.4.1 使用 max_depth 降低过拟合
- 3.4.4.2 通过min_impurity_decrease来优化模型
- 3.4.4.3 利用GridSearchCV求最优参数
- 4 sklearn回归决策树
- 4.1 参数列表
- 4.2 属性列表
- 5 参考文献
1 决策树
决策树(decision tree)是一种基本的分类与回归方法,其主要优点是模型具有可读性,分类速度快。学习时利用损失函数(正则化的极大似然函数)最小化的原则建立决策树模型。预测时,对新的数据,利用决策树模型进行分类。根据一组训练数据学习的决策树不是唯一的,与训练数据不相矛盾的(能对训练数据进行正确分类)决策树可能有多个,也可能一个也没有。我们需要的是一个与训练数据矛盾较小(训练误差小)的决策树,同时具有很好的泛化能力(测试误差小)。
决策树学习通常包括 3 个步骤:特征选择、决策树的生成和决策树的修剪。其中前两个步骤是几乎同时进行的。在每一步中,我们构建根节点,选择最优特征,并根据该特征对训练数据集进行划分(对应于模型的局部最优),使得各个子集有一个在当前条件下最好的分类,同时完成该层决策树的构建(如果这些自己已经能够被基本正确分类,那么构建叶结点,否则继续对其进行分割)。如此递归地进行下去,直到所有训练数据自己被基本正确分类,或者没有合适的特征为止。这样就生成了一棵决策树。之后我们需要对已生成的树进行自上而下的剪枝,将树变得简单,从而具有更好的泛化能力(对应于模型的全局最优)。具体地,就是剪掉过于细分的叶节点,使其回退到父结点,甚至更高的结点,然后将父结点或者更高的结点改为新的叶结点。
1.1 特征选择
数据有很多特征,那么在每一步中我们选择哪个特征?选择了特征之后又该如何在该特征上进行划分?这就是特征选择要做的事情。特征选择在预选区队训练数据有分类能力(与随机分类的结果有较大差异)的特征。特征选择有许多标准,我们根据这些标准对决策树学习的算法进行分类。比如ID3对应的标准是信息增益、C4.5对应的标准是信息增益比、CART对应的标准是基尼指数。下面给出这些标准的定义并结合实例进行说明。
1.1.1 基础定义
熵:熵(entropy)表示随机变量不确定性的度量,设 XXX 是一个取有限个值的离散随机变量,其概率分布为
P(X=xi)=pi,i=1,2,⋯ ,nP(X = x_i) = p_i, \quad i = 1, 2, \cdots, nP(X=xi)=pi,i=1,2,⋯,n
则随机变量 XXX 的熵定义为:
H(X)=−∑i=1npilogpi\color{Red}{H(X) = - \sum_{i = 1}^{n} p_i \log p_i}H(X)=−i=1∑npilogpi
若 pi=0p_i = 0pi=0 ,则定义 0log0=00 \log 0 = 00log0=0 。通常式中对数以 2 为底,这时熵的单位称作比特(bit),以 eee 和 10 为底的熵的单位称作纳特(nat)和哈托特(hat),因为熵只依赖于 XXX 的分布,因此也可写作 H(p)H(p)H(p) 。熵越大,随机变量的不确定性就越大。若熵中的概率由估计得到(特别是极大似然估计),这时熵称为经验熵(empirical entropy)。下图展示了二值随机变量熵 H(p)H(p)H(p) 随概率 ppp 变化的曲线。
条件熵:条件熵(conditional entropy) H(Y∣X)H(Y|X)H(Y∣X) 表示在已知随机变量 XXX 的条件下随机变量 YYY 的不确定性。随机变量 XXX 给定的条件下随机变量 YYY 的条件熵定义为:
H(Y∣X)=∑i=1npiH(Y∣X=xi)\color{Red}{H(Y|X) = \sum_{i = 1}^{n} p_i H(Y|X = x_i)}H(Y∣X)=i=1∑npiH(Y∣X=xi)
当条件熵中的概率由估计(特别是极大似然估计)得到时称为经验条件熵(empirical conditional entropy)。
信息增益:信息增益(information gain)表示得知特征 XXX 的信息而使得类 YYY 的信息的不确定性减少的程度,又称为互信息(mutual information)。特征 AAA 对训练数据集 DDD 的信息增益 g(D,A)g(D,A)g(D,A) ,定义为集合 DDD 的经验熵 H(D)H(D)H(D) 与特征 AAA 给定条件下 DDD 的经验条件熵 H(D∣A)H(D|A)H(D∣A) 之差,即
g(D,A)=H(D)−H(D∣A)\color{Red}{g(D, A) = H(D) - H(D|A)}g(D,A)=H(D)−H(D∣A)
信息增益比:特征 AAA 对训练数据集 DDD 的信息增益比 gR(D,A)g_R (D,A)gR(D,A) 定义为其信息增益 g(D,A)g(D,A)g(D,A) 与训练数据集 DDD 关于特征 AAA 的值的熵 HA(D)H_A (D)HA(D) 之比,即
gR(D,A)=g(D,A)HA(D)\color{Red}{g_R (D, A) = \frac{g(D, A)}{H_A (D)}}gR(D,A)=HA(D)g(D,A)
其中, HA(D)=−∑j=1S∣Di∣∣D∣log2∣Di∣∣D∣H_A (D) = - \sum_{j = 1}^{S} \frac{|D_i|}{|D|} \log_2 \frac{|D_i|}{|D|}HA(D)=−∑j=1S∣D∣∣Di∣log2∣D∣∣Di∣ , SSS 是特征 AAA 取值的个数
以信息增益作为划分训练数据集的特征,存在偏向于选择取值较多的特征的问题,比如在学生信息中我们用学号作为特征,那么显然一次性就可以划分结束,但是这样的结果没有实际意义。使用信息增益比可以对这一问题进行校正
基尼指数:分类问题中,假设有 KKK 个类,样本点属于第 kkk 类的概率为 pkp_kpk ,则概率分布的基尼指数(Gini index)定义为
Gini(p)=∑k=1Kpk(1−pk)=1−∑k=1Kpk2\color{Red}{Gini(p) = \sum_{k = 1}^{K} p_k (1 - p_k) = 1 - \sum_{k = 1}^{K}p_k^2}Gini(p)=k=1∑Kpk(1−pk)=1−k=1∑Kpk2
对于给定的样本集合 DDD ,其基尼指数为
Gini(D)=1−∑k=1K(∣Ck∣∣D∣)2\color{Red}{Gini(D) = 1 - \sum_{k = 1}^{K} \left(\frac{|C_k|}{|D|}\right)^2}Gini(D)=1−k=1∑K(∣D∣∣Ck∣)2
其中, CkC_kCk 是 DDD 中属于第 kkk 类的样本子集。
如果样本集合 DDD 根据特征 AAA 是否取某一可能值 aaa 被分割成 D1D_1D1 和 D2D_2D2 两部分,即
D1={(x,y)∈D∣A(x)=a},D2=D−D1D_1 = \{(x, y)\in D| A(x) = a\}, \ D_2 = D - D_1D1={(x,y)∈D∣A(x)=a}, D2=D−D1
则在特征 AAA 的条件下,集合 DDD 的基尼指数定义为
Gini(D,A)=∣D1∣∣D∣Gini(D1)+∣D2∣∣D∣Gini(D2)\color{Red}{Gini(D, A) = \frac{|D_1|}{|D|} Gini(D_1) + \frac{|D_2|}{|D|} Gini(D_2)}Gini(D,A)=∣D∣∣D1∣Gini(D1)+∣D∣∣D2∣Gini(D2)
直观来说,基尼指数反映了从数据集随机抽取两个样本,其类别标记不一致的概率,因此基尼指数越小,数据集纯度越高,基尼指数越大,数据集的不确定性越大。基尼指数 Gini(D)Gini(D)Gini(D) 表示集合 DDD 的不确定性,基尼指数 G(D,A)G(D, A)G(D,A) 表示经 A=aA = aA=a 分割后集合 DDD 的不确定性。基尼指数越大,样本集合的不确定性也就越大。下图展示了二分类问题中,基尼指数 Gini(p)Gini(p)Gini(p) 、熵之半 12H(p)\frac{1}{2}H(p)21H(p) 和分类误差率关于概率 ppp 的关系
1.1.2 最优特征标准
ID3:选择信息增益最大的特征作为最优特征
C4.5:选择信息增益比最大的特征作为最优特征
CART:选择基尼指数最小的特征及其对应的切分点作为最优特征与最优切分点
1.2 树的生成
1.2.1 ID3 算法
输入:训练数据集 DDD ,特征集 AAA ,阈值 ϵ\epsilonϵ
输出:决策树 TTT
(1) 若 DDD 中所有实例属于同一类 CkC_kCk ,则 TTT 为单结点树,并将类 CkC_kCk 作为该结点的类标记,返回 TTT ;
(2) 若 A=∅A = \varnothingA=∅ ,则 TTT 为单结点树,并将 DDD 中实例数最大的类 CkC_kCk 作为该结点的类标记,返回 TTT ;
(3) 否则,计算 AAA 中各特征对 DDD 的信息增益,选择信息增益最大的特征 AgA_gAg ;
(4) 如果 AgA_gAg 的信息增益小于阈值 ϵ\epsilonϵ ,则设置 TTT 为单结点树,并将 DDD 中实例数最大的类 CkC_kCk 作为该结点的类标记,返回 TTT ;
(5) 否则,对 AgA_gAg 的每一个可能值 aia_iai ,依 Ag=aiA_g = a_iAg=ai 将 DDD 分割为若干非空子集 DiD_iDi ,将 DiD_iDi 中实例数最大的类作为类标记,构建子结点,由结点及其子结点构成树 TTT ,返回 TTT ;
(6) 对第 iii 个子结点,以 DiD_iDi 为训练集,以 A−AgA - {A_g}A−Ag 为特征集,递归地调用步(1)~步(5),得到子树 TiT_iTi ,返回 TiT_iTi
1.2.2 C4.5 算法
输入:训练数据集 DDD ,特征集 AAA ,阈值 ϵ\epsilonϵ
输出:决策树 TTT
(1) 若 DDD 中所有实例属于同一类 CkC_kCk ,则 TTT 为单结点树,并将类 CkC_kCk 作为该结点的类标记,返回 TTT ;
(2) 若 A=∅A = \varnothingA=∅ ,则 TTT 为单结点树,并将 DDD 中实例数最大的类 CkC_kCk 作为该结点的类标记,返回 TTT ;
(3) 否则,计算 AAA 中各特征对 DDD 的信息增益比,选择信息增益比最大的特征 AgA_gAg ;
(4) 如果 AgA_gAg 的信息增益比小于阈值 ϵ\epsilonϵ ,则设置 TTT 为单结点树,并将 DDD 中实例数最大的类 CkC_kCk 作为该结点的类标记,返回 TTT ;
(5) 否则,对 AgA_gAg 的每一个可能值 aia_iai ,依 Ag=aiA_g = a_iAg=ai 将 DDD 分割为若干非空子集 DiD_iDi ,将 DiD_iDi 中实例数最大的类作为类标记,构建子结点,由结点及其子结点构成树 TTT ,返回 TTT ;
(6) 对第 iii 个子结点,以 DiD_iDi 为训练集,以 A−AgA - {A_g}A−Ag 为特征集,递归地调用步(1)~步(5),得到子树 TiT_iTi ,返回 TiT_iTi
1.2.2.1 如果特征是连续的
在C4.5中,对于连续型特征 x(j)x^{(j)}x(j) 采取了离散化处理(具体为二值化处理),比如某连续型特征在数据集上的取值从小到大为 {a1,a2,⋯ ,an}\{ a_1, a_2, \cdots, a_n\}{a1,a2,⋯,an},可以在每两个值之间选择一个切分点 bbb(可以是左闭右开区间中任意一个值),这样得到了一个切分点集合 {b1,b2,⋯ ,b)n−1}\{ b_1, b_2, \cdots, b){n - 1}\}{b1,b2,⋯,b)n−1}。基于 bib_ibi 我们把该特征划分为了两个部分 D−={x∣x(j)≤bi}D^{-} = \{x|x^{(j)} \le b_i\}D−={x∣x(j)≤bi} 和 D+={x∣x(j)>bi}D^{+} = \{x|x^{(j)} \gt b_i\}D+={x∣x(j)>bi}。于是我们对每个 bib_ibi 求信息增益(比),选择信息增益(比)最大的作为最优切分点。另外不同于离散型特征只作一次划分,可以对连续型属性进行多次划分,也就是说连续型特征可以多次使用。
1.2.2.2 如果数据中有缺失值
当缺失值较少时,可以直接忽略有缺失值的样本,但是当缺失值较多时就不能忽略。对于含有缺失值的样本有两种情况:(1) 特征值缺失;(2) 标签值缺失。在C4.5中,对两种情况做如下处理:
特征值缺失:我们假设特征 x(j)x^{(j)}x(j) 含有缺失值,且未缺失部分的样本数据集为 D~\tilde{D}D~,定义
ρ=∣D~∣∣D∣\rho = \frac{|\tilde{D}|}{|D|}ρ=∣D∣∣D~∣
p~k=D~k∣D~∣,k=1,2,⋯ ,K\tilde{p}_k = \frac{\tilde{D}_k}{|\tilde{D}|}, \quad k = 1, 2, \cdots, Kp~k=∣D~∣D~k,k=1,2,⋯,K
r~l=D~l∣D~∣,l=1,2,⋯ ,Sj\tilde{r}_l = \frac{\tilde{D}_l}{|\tilde{D}|}, \quad l = 1, 2, \cdots, S_jr~l=∣D~∣D~l,l=1,2,⋯,Sj
其中 ρ\rhoρ 表示完整数据的比例。D~k\tilde{D}_kD~k 表示完整数据中标签为第 kkk 类的样本数据集,所以 p~k\tilde{p}_kp~k 表示标签为第 kkk 类的样本在完整数据集中的比例。D~l\tilde{D}_lD~l 表示特征 x(j)x^{(j)}x(j) 取值为 lll 的数据集,SjS_jSj 是特征 x(j)x^{(j)}x(j) 的取值个数,所以 r~l\tilde{r}_lr~l 表示特征 x(j)x^{(j)}x(j) 取值为 lll 的样本在完整数据集中的比例。有了这些定义我们可以对信息增益公式做一些修改:
g(D,x(j))=ρ(H(D~)−∑l=1Sjr~lH(D~l))g(D, x^{(j)}) = \rho \left( H(\tilde{D}) - \sum_{l = 1}^{S_j}\tilde{r}_l H(\tilde{D}_l)\right)g(D,x(j))=ρ⎝⎛H(D~)−l=1∑Sjr~lH(D~l)⎠⎞
总的来说就是单独计算一个特征的信息增益时先考虑其完整数据的信息增益,然后乘一个衡量缺失比例的系数。
标签值缺失:若缺失样本 x\mathcal{x}x 在特征(对所有特征)x(j)x^{(j)}x(j) 上的特征值已知,那么将其划分到这个结点上。比如一个样本属性值 x(1)=x1(1),x(2)=x1(2)x^{(1)} = x^{(1)}_1, x^{(2)} = x^{(2)}_1x(1)=x1(1),x(2)=x1(2),那么将该样本划分到 x(1)=x1(1),x(2)=x1(2)x^{(1)} = x^{(1)}_1, x^{(2)} = x^{(2)}_1x(1)=x1(1),x(2)=x1(2) 的叶结点,并且样本的权值 wx\mathcal{w}_{\mathcal{x}}wx保持不变。如果同时有某个特征值缺失,比如特征 x(j)x^{(j)}x(j) 缺失,那么先将样本点划分到特征 x(j)x^{(j)}x(j) 分支后的所有结点中,并且在各结点中的权值变为 r~l⋅wx\tilde{r}_l \cdot \mathcal{w}_{\mathcal{x}}r~l⋅wx
1.2.3 CART 算法
1.2.3.1 CART 分类
分类与回归树(Classification And Regression Tree,CART)即可用于分类也可用于回归,CART假设决策树是二叉树,内部结点特征的取值为“是”和“否”,左分支是取值为“是”的分支,右分支是取值为“否”的分支。
输入:训练数据集 DDD ,停止计算的条件
输出:CART 决策树
根据训练数据集,从根结点开始,递归地对每个结点进行以下操作,构建二叉决策树:
(1) 设结点的训练数据集为 DDD ,计算现有特征对该数据集的基尼指数 Gini(D)Gini(D)Gini(D) 。此时对每一个特征 AAA ,对其可能取的每一个值 aaa ,根据样本点对 A=aA = aA=a 的测试为“是”或“否”将 DDD 分割成 D1D_1D1 和 D2D_2D2 两部分,然后计算 A=aA = aA=a 时的基尼指数 Gini(D,A)Gini(D, A)Gini(D,A) ;
(2) 在所有可能的特征 AAA 以及它们所有可能的切分点中,选择基尼指数最小的特征及其对应的切分点作为最优特征与最优切分点。依最优特征与最优切分点,从现结点生成两个子结点,将训练数据集依特征分配到两个子结点中去;
(3) 对两个子结点递归地调用 (1),(2),直到满足停止条件;
(4) 生成 CART 决策树
算法停止计算的条件是结点中的样本个数小于预定阈值,或样本集的基尼指数小于预定阈值(样本基本属于同一类),或者没有更多特征。
1.2.3.2 CART 回归
一个回归树把特征空间的一个划分 Rm,m=1,2,⋯ ,MR_m, m = 1, 2, \cdots, MRm,m=1,2,⋯,M 映射到一个固定的输出值 cmc_mcm,回归模型可以表示为
f(x)=∑m=1McmI(x∈Rm)f(x) = \sum_{m = 1}^{M}c_m I(x \in R_m)f(x)=m=1∑McmI(x∈Rm)
当输入空间的划分确定后,可以用平方误差 ∑xi∈Rm(yi−f(xi))2\sum_{x_i \in R_m} {(y_i - f(x_i))}^2∑xi∈Rm(yi−f(xi))2 来表示回归树对于训练误差的预测误差,用平方误差最小的准则求解每个单元上的最优输出值,即均值(如果是绝对值误差最小,就是中位数)。那么重点就是怎样进行空间的划分。
我们先寻找最优切分点,对于一个特征 x(j)x^{(j)}x(j),我们设切分点 s(j)s(j)s(j) 将其特征空间划分为两部分
R1(j,s(j))={x∣x(j)≤s(j)},R2(j,s(j))={x∣x(j)>s(j)}R_1 (j, s(j)) = \{x | x^{(j)} \le s(j)\}, \ R_2 (j, s(j)) = \{x | x^{(j)} \gt s(j)\}R1(j,s(j))={x∣x(j)≤s(j)}, R2(j,s(j))={x∣x(j)>s(j)}
于是,最优切分点就是使数据集在 R1,R2R_1, R_2R1,R2 上平方误差最小的点。令
c1^(j,s(j))=yiˉ,xi∈R1(j,s(j))\hat{c_1} (j, s(j)) = \bar{y_i}, \ x_i \in R_1 (j, s(j))c1^(j,s(j))=yiˉ, xi∈R1(j,s(j))
c2^(j,s(j))=yiˉ,xi∈R2(j,s(j))\hat{c_2} (j, s(j)) = \bar{y_i}, \ x_i \in R_2 (j, s(j))c2^(j,s(j))=yiˉ, xi∈R2(j,s(j))
则特征 jjj 的最优切分点s(j) 使下式达到最小
g(s)=minc1∑xi∈R1(yi−c1(j,s(j)))2+minc2∑xi∈R1(yi−c1(j,s(j)))2g(s) = \mathop{\min}_{c_1} \sum_{x_i \in R_1}{(y_i - c_1 (j, s(j)))}^2 + \mathop{\min}_{c_2} \sum_{x_i \in R_1}{(y_i - c_1 (j, s(j)))}^2g(s)=minc1xi∈R1∑(yi−c1(j,s(j)))2+minc2xi∈R1∑(yi−c1(j,s(j)))2
这样对于所有的特征,我们得到了一个特征与最优切分点对 (j,s(j))(j, s(j))(j,s(j)) ,下一步就是选取最优特征。令
m(j)=minsg(s)m(j) = \mathop{\min}_{s} g(s)m(j)=minsg(s)
于是最优特征就是最小 m(j)m(j)m(j) 对应的特征,我们按照该特征及其最优切分点对数据集进行划分。接着重复上述过程,直到满足停止条件。
输入:训练数据集 DDD
输出:回归树 f(x)f(x)f(x)
在训练数据集所在的输入空间中,递归地将每个区域划分为两个子区域并决定每个子区域上的输出值,构建二叉决策树:
(1) 选择最优切分变量 jjj 与切分点 sss,求
minj,s[minc1∑xi∈R1(j,s)+minc1∑xi∈R1(j,s)]\mathop{\min}_{j,s}\left[ \mathop{\min}_{c_1} \sum_{x_i \in R_1 (j, s)} + \mathop{\min}_{c_1} \sum_{x_i \in R_1 (j, s)} \right]minj,s⎣⎡minc1xi∈R1(j,s)∑+minc1xi∈R1(j,s)∑⎦⎤
遍历变量 jjj,对固定的切分变量 jjj 扫描切分点 sss,选择使上式达到最小值的对 (j,s)(j, s)(j,s);
(2) 用选定的对 (j,s)(j, s)(j,s) 划分区域并决定相应的输出值:
R1(j,s)={x∣x(j)≤s(j)},R2(j,s)={x∣x(j)>s(j)}R_1 (j, s) = \{x | x^{(j)} \le s(j)\}, \ R_2 (j, s) = \{x | x^{(j)} \gt s(j)\}R1(j,s)={x∣x(j)≤s(j)}, R2(j,s)={x∣x(j)>s(j)}
c1^(j,s(j))=yiˉ,xi∈R1(j,s(j))\hat{c_1} (j, s(j)) = \bar{y_i}, \ x_i \in R_1 (j, s(j))c1^(j,s(j))=yiˉ, xi∈R1(j,s(j))
c2^(j,s(j))=yiˉ,xi∈R2(j,s(j))\hat{c_2} (j, s(j)) = \bar{y_i}, \ x_i \in R_2 (j, s(j))c2^(j,s(j))=yiˉ, xi∈R2(j,s(j))
(3) 继续对两个子区域调用步骤(1),(2),直至满足停止条件;
(4) 将输入空间划分为 MMM 个区域 R1,R2,⋯ ,RMR_1, R_2, \cdots, R_MR1,R2,⋯,RM,生成决策树:
f(x)=∑m=1Mcm^I(x∈Rm)f(x) = \sum_{m = 1}^{M}\hat{c_m}I(x \in R_m)f(x)=m=1∑Mcm^I(x∈Rm)
1.2.4 ID3 Vs C4.5 Vs CART
三个算法最明显的区别就是对于特征选择的策略不同,不过目的都是降低数据集的不确定性。具体来说,ID3使用信息增益来衡量不确定性,C4.5使用信息增益比来衡量不确定性,CART使用基尼指数来衡量不确定性。
具体比较ID3和C4.5:信息增益等于熵减去条件熵。信息增益越大说明一个特征减少数据集不确定性的能力越强,也就是该特征的分类能力越强。但是也有例外的情况,考虑一个极端例子,对班上的同学进行分类,如果我们用学号作为特征,那么每个学生分成了一类,得到了深度为2的树,但显然这样的分类没有任何意义。于是我们引入对树的分支(一个特征的特征值)的惩罚,即数据集关于特征的熵,从而得到信息增益比。因此,当存在特征有较多可取的值时,C4.5比ID3表现更好。另一个不同点是ID3只能处理离散型特征,而C4.5可以通过对连续型特征进行离散化处理来对连续型特征进行分支
对于CART:最直观的感觉就是,基尼指数好算得多,毕竟不用求对数。另一个明显的区别是CART树是一个二叉树,这也进一步简化了求基尼指数。但也正是因为这一结构,CART树存在深度过大的问题,所以更适合处理二值特征问题。此外,CART树可以处理回归问题。
1.3 树的剪枝
前面生成的决策树往往对训练数据的分类很准确,但是对未知的测试数据的分类却没有那么准确,即出现过拟合现象。解决这一问题的办法就是考虑决策树的复杂度,对已生成的决策树进行剪枝(pruning)。这一过程往往通过极小化决策树整体的损失函数来实现。
设树 TTT 的叶结点个数为 ∣T∣|T|∣T∣ , ttt 是树 TTT 的叶结点,该结点有 NtN_tNt 个样本点,其中 kkk 类样本点有 NtkN_{tk}Ntk 个, k=1,2,⋯ ,Kk = 1, 2, \cdots, Kk=1,2,⋯,K , Ht(T)H_t(T)Ht(T) 为叶结点 ttt 上的经验熵, α≥0\alpha \ge 0α≥0 为参数,则决策树的损失函数可以定义为
Cα(T)=∑t=1∣T∣NtHt(T)C_\alpha (T) = \sum_{t = 1}^{|T|}N_t H_t (T)Cα(T)=t=1∑∣T∣NtHt(T)
其中经验熵为
Ht(T)=−∑k=1KNtkNtlogNtkNtH_t (T) = - \sum_{k = 1}^{K}\frac{N_{tk}}{N_t} \log \frac{N_{tk}}{N_t}Ht(T)=−k=1∑KNtNtklogNtNtk
从损失函数表达式可以看出,其第一项表示模型对训练数据的预测误差,第二项为对模型复杂度的惩罚。较大的 α\alphaα 促使选择更简单的模型,当 α=0\alpha = 0α=0 时,不考虑模型的复杂度。剪枝就是当 α\alphaα 确定时,选择损失函数最小的模型。
可以看出,决策树生成只考虑了通过信息增益(或信息增益比、基尼指数)对训练数据进行更好的拟合,而决策树的剪枝通过优化损失函数还考虑了减小模型的复杂度。决策树生成学习局部的模型,而决策树剪枝学习整体的模型。
1.3.1 ID3 & C4.5
1.3.1.1 后剪枝 & CCP 原则
输入:生成算法的整个树 TTT ,参数 α\alphaα
输出:修剪后的子树 TαT_\alphaTα
(1) 计算每个结点的经验熵;
(2) 递归地从树的叶结点向上回缩:如果回缩后整体树的损失函数小于等于回缩前的损失函数,则进行剪枝,即将父结点变为新的叶结点;
(3) 返回(2),直至不能继续为止,得到损失函数最小的子树 TαT_\alphaTα。
1.3.1.2 预剪枝 & REP 原则
每进行一次划分,对划分前后的树计算其在验证集上的准确率,如果划分后准确率降低,则不进行划分,否则继续进行树的生成
1.3.2 CART(后剪枝 & CCP)
CART 的剪枝使用同样形式的损失函数:
Cα(T)=C(T)+α∣T∣C_\alpha (T) = C(T) + \alpha |T|Cα(T)=C(T)+α∣T∣
其中, TTT 为任意子树, C(T)C(T)C(T) 为对训练数据的预测误差(基尼指数), ∣T∣|T|∣T∣ 为子树的叶结点个数, α\alphaα 为参数, Cα(T)C_\alpha (T)Cα(T) 为参数是 α\alphaα 时的子树 TTT 的整体损失。对于CART树的剪枝我们分成两个步骤进行。
1. 剪枝并得到子树序列
从整体树 T0T_0T0 开始剪枝,对 T0T_0T0 的任意内部结点 ttt ,我们进行下列计算
显然当 α=0\alpha = 0α=0 时,上面的损失函数更小,当 α\alphaα 很大时下面的损失函数更小,于是存在 α(t)=C(t)−C(Tt)∣Tt∣−1\alpha (t) = \frac{C(t) - C(T_t)}{|T_t| - 1}α(t)=∣Tt∣−1C(t)−C(Tt) 使得两个损失函数相同,这时上面的树结点更少,于是对 TtT_tTt 进行剪枝得到子树 TαT_\alphaTα
因此,对于 T0T_0T0 中的每个结点 ttt ,我们可以求得对应的 α(t)\alpha (t)α(t) 和一个剪枝后的子树 TαT_\alphaTα (α0=0\alpha_0 = 0α0=0 对应整体树 T0T_0T0)。将刚刚得到的 α\alphaα 从小到大排列并记为 α0=0,α1,α2,⋯\alpha_0 = 0, \alpha_1, \alpha_2, \cdotsα0=0,α1,α2,⋯ , TαT_\alphaTα 进行对应的排列并记为 T0,T1,T2,⋯T_0, T_1, T_2, \cdotsT0,T1,T2,⋯ ,于是 TiT_iTi 为区间 [αi,αi+1][\alpha_i, \alpha_{i+1}][αi,αi+1] 的最优子树。
相比ID3和C4.5算法的剪枝, α\alphaα 没有给出一个固定的值,需要进一步判断这一系列子树中哪一个是最优的
2. 通过交叉验证法在子树序列中选取最优子树
对第 1 步中的到的子树序列在验证数据集上进行交叉验证(测试各子树的平方误差或基尼指数,平方误差或基尼指数最小的决策树被认为是最优的决策树)。当最优子树 TkT_kTk 确定后,对应的 αk\alpha_kαk 也确定了,即得到最优决策树 TαT_\alphaTα
下面是书中给出的伪代码,感觉是有问题的,会在之后提出我的问题
输入:CART算法生成的决策树 T0T_0T0
输出:最优决策树 TαT_\alphaTα
(1) 设 k=0k = 0k=0 , T=T0T = T_0T=T0 ;
(2) 设 α=+∞\alpha = + \inftyα=+∞ ;
(3) 自下而上地对各个内部结点 ttt 计算(一个问题是内部结点是否包含根结点,如果包含那么可能与步骤(6)的结束条件产生矛盾) C(Tt)C(T_t)C(Tt) , ∣Tt∣|T_t|∣Tt∣ 以及
α(t)=C(t)−C(Tt)∣Tt∣−1\alpha (t) = \frac{C(t) - C(T_t)}{|T_t| - 1}α(t)=∣Tt∣−1C(t)−C(Tt)
α=min(α,α(t))\alpha = \min (\alpha, \alpha(t))α=min(α,α(t))
(4) 对 α(t)=α\alpha (t) = \alphaα(t)=α 的内部结点 ttt 进行剪枝(如果这轮迭代求得的 α(t)\alpha (t)α(t) 比前一轮大,那么就不需要剪枝),并对叶结点 ttt 以多数表决法决定其类,得到树 TTT ;
(5) 设 k=k+1k = k + 1k=k+1 , αk=α\alpha_k = \alphaαk=α , Tk=TT_k = TTk=T ;
(6) 如果 TkT_kTk 不是由根结点及两个叶结点构成的树,则回到步骤(3),否则令 Tk=TnT_k = T_nTk=Tn ;
(7) 采用交叉验证法在子树序列 T0,T1,⋯ ,TnT_0, T_1, \cdots, T_nT0,T1,⋯,Tn 中选取最优子树 TαT_\alphaTα 。
1.3.2.1 假设——给定 α\alphaα,一定存在使损失函数最小的子树,且这样的子树唯一
我们假设有下面这样一棵树,记为 T0T_0T0,对于给定的 α\alphaα,它有两个最优子树 T1,T2T_1, T_2T1,T2,且 Cα(T1)=Cα(T2)C_\alpha(T_1) = C_\alpha(T_2)Cα(T1)=Cα(T2),因为剪枝操作是已经完成的,所以对于结点 t1,t2t_1, t_2t1,t2,有 C(t1)≤C(Tt1),C(t2)≤C(Tt2)C(t_1) \le C(T_{t_1}), \ C(t_2) \le C(T_{t_2})C(t1)≤C(Tt1), C(t2)≤C(Tt2),那么在树 T1T_1T1 中就应该继续在 t2t_2t2 结点处进行剪枝,得到 T3T_3T3,那么一定有 Cα(T3)<Calpha(T1)C_\alpha(T_3) \lt C_alpha(T_1)Cα(T3)<Calpha(T1),这与 T1T_1T1 是最优子树矛盾。
1.3.2.2 没搞懂的问题
伪代码问题(由步骤(3)是否在当时就计算出每个内部结点对应的α(t)\alpha (t)α(t)引起,如果认为是那么就不需要考虑下面的问题):
如果只是计算一个节点的α(t)\alpha (t)α(t)就向下进行:
如果是计算全部节点的α(t)\alpha (t)α(t)再向下进行应该会是下面的情况
1.3.3 预剪枝 Vs 后剪枝
预剪枝是在生成决策树的过程中进行的,每进行一次分支就进行判断该分支的必要性(即剪枝),对剪枝后的树,用验证机上的数据计算其准确率,如果分支后准确率更高,就不进行剪枝。后剪枝是先生成树,然后自下而上地考察内部结点,若剪枝引起精度上升就进行剪枝。
实际操作能够发现,后剪枝通常比预剪枝保留更多分支,一般情形下后剪枝决策树欠拟合的风险更小,泛化性能也更高。但是后剪枝的过程是在树生成以后进行的,需要对所有内部结点逐一考察,因此时间上的花销更大。而预剪枝虽然降低了过拟合的风险,但是有些分支当前划分虽然不能提升泛化能力,但是在其基础上进行的后续划分却有可能导致性能显著提高(如从第3层到第4层,泛化性能下降,即树在验证集上的准确率降低,因此停止了划分。但是如果继续划分下去,在第5层可能获得比第3层高的准确率)。预剪枝基于“贪心”本质禁止这些分支展开,给预剪枝决策树带来了欠拟合的风险。
1.3.4 CCP Vs REP Vs PEP
CCP(Cost-Complelexity Pruning,代价复杂度剪枝)就是前面讲的CART的剪枝方法。方法自下而上地计算每个内部结点的损失,得到最优子树序列,然后根据其在验证集上的表现选出最优子树。
REP(Reduced-Error Pruning,错误率降低剪枝)借助决策树在验证集上的准确率判断是否进行剪枝。
PEP(Pessimistic-Error Pruning,悲观剪枝法)采取自上而下的剪枝并且不需要验证集,因此剪枝后错分率必定上升,所以计算错分率时添加了0.5的惩罚因子。考虑一个叶结点 ttt 中有 NtN_tNt 个样本,EtE_tEt 个错分样本。那么该点的错分率 εt=Et+0.5Nt\varepsilon_t = \frac{E_t + 0.5}{N_t}εt=NtEt+0.5,如果树 TTT 有 ∣T∣|T|∣T∣ 个叶结点,那么树 TTT 的错分率为 εT=∑t=1∣T∣Et+0.5Nt=∑t=1∣T∣(Et+0.5)N\varepsilon_T = \sum_{t = 1}^{|T|} \frac{E_t + 0.5}{N_t} = \frac{\sum_{t = 1}^{|T|}(E_t + 0.5)}{N}εT=∑t=1∣T∣NtEt+0.5=N∑t=1∣T∣(Et+0.5),假设树 TTT 的样本服从二项分布 B(N,εT)B(N, \varepsilon_T)B(N,εT) ,那么其期望误判个数为 N×εT=∑t=1∣T∣(Et+0.5)N \times \varepsilon_T = \sum_{t = 1}^{|T|}(E_t + 0.5)N×εT=∑t=1∣T∣(Et+0.5),标准差为 N×εT×(1−εT)\sqrt{N \times \varepsilon_T \times (1 - \varepsilon_T)}N×εT×(1−εT)。当剪枝前的误判个数大于剪枝后的误判个数一个标准差时就决定剪枝
1.4 多变量决策树
多变量决策树(multivariate decision tree)并不是多个特征的意思,而是在进行分支时不仅仅只看一个特征的取值,而是多个特征的线性组合。比如单变量决策树进行分支的依据可能是 x(1)≤5.5,x(1)>5.5x^{(1)} \le 5.5, x^{(1)} \gt 5.5x(1)≤5.5,x(1)>5.5 或者 x(2)≤7.5,x(2)>7.5x^{(2)} \le 7.5, x^{(2)} \gt 7.5x(2)≤7.5,x(2)>7.5 ,而多变量决策树进行分支的标准可能是 0.3×x(1)+0.7×x(2)≤0,0.3×x(1)+0.7×x(2)>00.3\times x^{(1)} + 0.7\times x^{(2)}\le 0, 0.3\times x^{(1)} + 0.7\times x^{(2)}\gt 00.3×x(1)+0.7×x(2)≤0,0.3×x(1)+0.7×x(2)>0。体现在特征空间中,单变量决策树对空间的划分是平行于坐标轴的,而多变量决策树是一条曲线。虽然单变量决策树有很好的解释性,但当学习任务非常复杂以至于需要进行多段划分时,多变量决策树就会变现的更好也更接近真实函数。下图中黑色折线就是多段的单变量划分结果,而红色曲线是多变量决策树的划分结果。
1.5 多输出决策树
有的时候我们想要得到的输出结果不是只有一个,比如我们根据某地的气象数据预测其未来某段时间的风向、风速和是否降雨等,显然这些输出不属于同一个问题,不能归结为单一输出的多标签问题。如果输出之间完全独立,这时我们可以对每一个输出建立一个单独的决策树进行预测,但是当输出变量之间有较强的相关性时,建立多输出决策树是一个更好的选择。
1.6 C5.0
C5.0是C4.5算法的改进。由于C4.5算法只适合于能够驻留于内存的数据集,面对大数据及十分乏力,因此提出了C5.0算法。C5.0使用熵的下降速度(因为找不到相关资料,这里不清楚这个速度是什么东西,个人感觉还是信息增益比啊)作为特征选择的依据,采用了Boosting方式提高了模型准确率;计算速度更快,占用内存更少;在面对数据遗漏和输入字段很多时表现稳健;相比其他模型更易于理解,模型退出的规则有非常直观的解释。
1.7 随机森林
决策树模型的最大问题是方差很大,不稳定,很小的数据扰动就可能产生一棵完全不同的决策树。解决这一问题的办法是集成学习,组合多棵决策树的预测结果进行预测,也就是非常有名的随机森林。这一部分笔记等到学习集成学习的时候再进行整理。
1.8 实例
1.8.1 决策树分类
通过下面贷款申请样本的数据学习一个贷款申请的决策树,用以对未来的贷款申请进行分类,即当新的客户提出贷款申请时,根据申请人的特征利用决策树决定是否批准贷款申请。
数据集用 DDD 表示,年龄、有工作、有自己的房子和信贷情况4个特征用 A1,A2,A3,A4A_1, A_2, A_3, A_4A1,A2,A3,A4 表示,并以 1,2,31, 2, 31,2,3 表示年龄的值为青年、中年、老年,以 1,21, 21,2 表示有工作和有自己的房子的值为是和否,以 1,2,31, 2, 31,2,3 表示信贷情况的值为非常好、好和一般。
1.8.1.1 ID3
计算 DDD 的经验熵
H(D)=−(915×log2915+615×log2615)=0.971H(D) = - \left( \frac{9}{15} \times \log_2 \frac{9}{15} + \frac{6}{15} \times \log_2 \frac{6}{15} \right) = 0.971H(D)=−(159×log2159+156×log2156)=0.971
计算特征 AiA_iAi 给定条件下 DDD 的条件经验熵
H(D∣A1)=515H(D∣A1=1)+515H(D∣A1=2)+515H(D∣A1=3)=515(−25log225−35log235)+515(−35log235−25log225)+515(−45log245−15log215)=0.888H(D∣A2)=515H(D∣A2=1)+1015H(D∣A2=2)=0.647H(D∣A3)=615H(D∣A3=1)+915H(D∣A3=2)=0.551H(D∣A4)=515H(D∣A4=1)+615H(D∣A4=2)+415H(D∣A4=3)=0.647\begin{aligned} H(D | A_1) & = \frac{5}{15}H(D | A_1 = 1) + \frac{5}{15}H(D | A_1 = 2) + \frac{5}{15}H(D | A_1 = 3) \\ & = \frac{5}{15}\left( -\frac{2}{5} \log_2 \frac{2}{5} -\frac{3}{5} \log_2 \frac{3}{5}\right) + \frac{5}{15}\left( -\frac{3}{5} \log_2 \frac{3}{5} -\frac{2}{5} \log_2 \frac{2}{5}\right) + \frac{5}{15}\left( -\frac{4}{5} \log_2 \frac{4}{5} -\frac{1}{5} \log_2 \frac{1}{5}\right) \\ & = 0.888 \\ H(D | A_2) & = \frac{5}{15}H(D | A_2 = 1) + \frac{10}{15}H(D | A_2 = 2) \\ & = 0.647 \\ H(D | A_3) & = \frac{6}{15}H(D | A_3 = 1) + \frac{9}{15}H(D | A_3 = 2) \\ & = 0.551 \\ H(D | A_4) & = \frac{5}{15}H(D | A_4 = 1) + \frac{6}{15}H(D | A_4 = 2) + \frac{4}{15}H(D | A_4 = 3) \\ & = 0.647 \end{aligned}H(D∣A1)H(D∣A2)H(D∣A3)H(D∣A4)=155H(D∣A1=1)+155H(D∣A1=2)+155H(D∣A1=3)=155(−52log252−53log253)+155(−53log253−52log252)+155(−54log254−51log251)=0.888=155H(D∣A2=1)+1510H(D∣A2=2)=0.647=156H(D∣A3=1)+159H(D∣A3=2)=0.551=155H(D∣A4=1)+156H(D∣A4=2)+154H(D∣A4=3)=0.647
计算信息增益
g(D,A1)=H(D)−H(D∣A1)=0.083g(D,A2)=H(D)−H(D∣A2)=0.324g(D,A3)=H(D)−H(D∣A3)=0.420g(D,A4)=H(D)−H(D∣A4)=0.363\begin{aligned} g(D, A_1) & = H(D) - H(D | A_1) = 0.083 \\ g(D, A_2) & = H(D) - H(D | A_2) = 0.324 \\ g(D, A_3) & = H(D) - H(D | A_3) = 0.420 \\ g(D, A_4) & = H(D) - H(D | A_4) = 0.363 \\ \end{aligned}g(D,A1)g(D,A2)g(D,A3)g(D,A4)=H(D)−H(D∣A1)=0.083=H(D)−H(D∣A2)=0.324=H(D)−H(D∣A3)=0.420=H(D)−H(D∣A4)=0.363
DDD 关于特征 A3A_3A3 的信息增益最大,所以选择 A3A_3A3 为最优特征
根据 A3A_3A3 对数据集进行分割后,得到了两个新的子集 D1,D2D_1, D_2D1,D2,其中 D1D_1D1 都是同类样本,不需要再进行细分,D2D_2D2 中有 3 个样本类别为“是”,6 个为“否”,需要进行进一步划分
计算 DDD 的经验熵
H(D2)=−(13×log213+23×log223)=0.918H(D_2) = - \left( \frac{1}{3} \times \log_2 \frac{1}{3} + \frac{2}{3} \times \log_2 \frac{2}{3} \right) = 0.918H(D2)=−(31×log231+32×log232)=0.918
计算特征 AiA_iAi 给定条件下 DDD 的条件经验熵
H(D2∣A1)=49H(D2∣A1=1)+29H(D2∣A1=2)+39H(D2∣A1=3)=49(−14log214−34log234)+29×0+39(−23log223−13log213)=0.667H(D2∣A2)=39H(D2∣A2=1)+69H(D2∣A2=2)=0H(D2∣A4)=49H(D2∣A4=1)+49H(D2∣A4=2)+19H(D2∣A4=3)=0.444\begin{aligned} H(D_2 | A_1) & = \frac{4}{9}H(D_2 | A_1 = 1) + \frac{2}{9}H(D_2 | A_1 = 2) + \frac{3}{9}H(D_2 | A_1 = 3) \\ & = \frac{4}{9}\left( -\frac{1}{4} \log_2 \frac{1}{4} -\frac{3}{4} \log_2 \frac{3}{4}\right) + \frac{2}{9}\times 0 + \frac{3}{9}\left( -\frac{2}{3} \log_2 \frac{2}{3} -\frac{1}{3} \log_2 \frac{1}{3}\right) \\ & = 0.667 \\ H(D_2 | A_2) & = \frac{3}{9}H(D_2 | A_2 = 1) + \frac{6}{9}H(D_2 | A_2 = 2) \\ & = 0 \\ H(D_2 | A_4) & = \frac{4}{9}H(D_2 | A_4 = 1) + \frac{4}{9}H(D_2 | A_4 = 2) + \frac{1}{9}H(D_2 | A_4 = 3) \\ & = 0.444 \end{aligned}H(D2∣A1)H(D2∣A2)H(D2∣A4)=94H(D2∣A1=1)+92H(D2∣A1=2)+93H(D2∣A1=3)=94(−41log241−43log243)+92×0+93(−32log232−31log231)=0.667=93H(D2∣A2=1)+96H(D2∣A2=2)=0=94H(D2∣A4=1)+94H(D2∣A4=2)+91H(D2∣A4=3)=0.444
计算信息增益
g(D2,A1)=H(D2)−H(D2∣A1)=0.251g(D2,A2)=H(D2)−H(D2∣A2)=0.918g(D2,A4)=H(D2)−H(D2∣A4)=0.474\begin{aligned} g(D_2, A_1) & = H(D_2) - H(D_2 | A_1) = 0.251 \\ g(D_2, A_2) & = H(D_2) - H(D_2 | A_2) = 0.918 \\ g(D_2, A_4) & = H(D_2) - H(D_2 | A_4) = 0.474 \\ \end{aligned}g(D2,A1)g(D2,A2)g(D2,A4)=H(D2)−H(D2∣A1)=0.251=H(D2)−H(D2∣A2)=0.918=H(D2)−H(D2∣A4)=0.474
D2D_2D2 关于特征 A2A_2A2 的信息增益最大,所以选择 A2A_2A2 为最优特征
此时所有子集的样本点都是同一类,结束
剪枝
记前面生成的决策树为 T0T_0T0 ,因为D1,D21,D22D_1, D_{21}, D_{22}D1,D21,D22 中的样本点都是同一类,所以 H(D1),H(D21),H(D22)H(D_1), H(D_{21}), H(D_{22})H(D1),H(D21),H(D22)都是 0 ,叶结点个数 ∣T0∣=3|T_0| = 3∣T0∣=3,易求得 Cα(T0)=3αC_\alpha (T_0) = 3\alphaCα(T0)=3α
若在 D2D_2D2 处进行剪枝,记剪枝后的树为 T1T_1T1,对于叶结点 D1,D2D_1, D_2D1,D2,知道 H(D1)=0,H(D2)=0.918H(D_1) = 0, H(D_2) = 0.918H(D1)=0,H(D2)=0.918,于是
Cα(T1)=6H(D1)+9H(D2)+2α=8.262+2αC_\alpha(T_1) = 6\ H(D_1) + 9\ H(D_2) + 2\alpha = 8.262 + 2\alphaCα(T1)=6 H(D1)+9 H(D2)+2α=8.262+2α
故当 3α≥8.262+2α3\alpha \ge 8.262 + 2\alpha3α≥8.262+2α,即 α≥8.262\alpha \ge 8.262α≥8.262 时应该剪枝(取等时根据奥卡姆剃刀原则选择结点更少的)
若继续对 T1T_1T1 进行剪枝,记剪枝后的树为 T2T_2T2, 即以根结点为单结点的树,H(D)=0.971H(D) = 0.971H(D)=0.971,Cα(T2)=15H(D)+α=14.565+αC_\alpha (T_2) = 15 H(D) + \alpha = 14.565 + \alphaCα(T2)=15H(D)+α=14.565+α,故当 8.262+2α≥14.565+α8.262 + 2\alpha \ge 14.565 + \alpha8.262+2α≥14.565+α,即 α≥6.303\alpha \ge 6.303α≥6.303 时应当剪枝
综上当 0≤α<6.3030 \le \alpha \lt 6.3030≤α<6.303 时,不需要剪枝,最终子树为整体树 T0T_0T0,当 α≥6.303\alpha \ge 6.303α≥6.303 时修剪后的子树为以根结点为单结点的树 T2T_2T2
1.8.1.2 C4.5
计算 DDD 的经验熵
H(D)=−(915×log2915+615×log2615)=0.971H(D) = - \left( \frac{9}{15} \times \log_2 \frac{9}{15} + \frac{6}{15} \times \log_2 \frac{6}{15} \right) = 0.971H(D)=−(159×log2159+156×log2156)=0.971
计算特征 AiA_iAi 给定条件下 DDD 的条件经验熵
H(D∣A1)=515H(D∣A1=1)+515H(D∣A1=2)+515H(D∣A1=3)=515(−25log225−35log235)+515(−35log235−25log225)+515(−45log245−15log215)=0.888H(D∣A2)=515H(D∣A2=1)+1015H(D∣A2=2)=0.647H(D∣A3)=615H(D∣A3=1)+915H(D∣A3=2)=0.551H(D∣A4)=515H(D∣A4=1)+615H(D∣A4=2)+415H(D∣A4=3)=0.647\begin{aligned} H(D | A_1) & = \frac{5}{15}H(D | A_1 = 1) + \frac{5}{15}H(D | A_1 = 2) + \frac{5}{15}H(D | A_1 = 3) \\ & = \frac{5}{15}\left( -\frac{2}{5} \log_2 \frac{2}{5} -\frac{3}{5} \log_2 \frac{3}{5}\right) + \frac{5}{15}\left( -\frac{3}{5} \log_2 \frac{3}{5} -\frac{2}{5} \log_2 \frac{2}{5}\right) + \frac{5}{15}\left( -\frac{4}{5} \log_2 \frac{4}{5} -\frac{1}{5} \log_2 \frac{1}{5}\right) \\ & = 0.888 \\ H(D | A_2) & = \frac{5}{15}H(D | A_2 = 1) + \frac{10}{15}H(D | A_2 = 2) \\ & = 0.647 \\ H(D | A_3) & = \frac{6}{15}H(D | A_3 = 1) + \frac{9}{15}H(D | A_3 = 2) \\ & = 0.551 \\ H(D | A_4) & = \frac{5}{15}H(D | A_4 = 1) + \frac{6}{15}H(D | A_4 = 2) + \frac{4}{15}H(D | A_4 = 3) \\ & = 0.647 \end{aligned}H(D∣A1)H(D∣A2)H(D∣A3)H(D∣A4)=155H(D∣A1=1)+155H(D∣A1=2)+155H(D∣A1=3)=155(−52log252−53log253)+155(−53log253−52log252)+155(−54log254−51log251)=0.888=155H(D∣A2=1)+1510H(D∣A2=2)=0.647=156H(D∣A3=1)+159H(D∣A3=2)=0.551=155H(D∣A4=1)+156H(D∣A4=2)+154H(D∣A4=3)=0.647
计算信息增益
g(D,A1)=H(D)−H(D∣A1)=0.083g(D,A2)=H(D)−H(D∣A2)=0.324g(D,A3)=H(D)−H(D∣A3)=0.420g(D,A4)=H(D)−H(D∣A4)=0.363\begin{aligned} g(D, A_1) & = H(D) - H(D | A_1) = 0.083 \\ g(D, A_2) & = H(D) - H(D | A_2) = 0.324 \\ g(D, A_3) & = H(D) - H(D | A_3) = 0.420 \\ g(D, A_4) & = H(D) - H(D | A_4) = 0.363 \\ \end{aligned}g(D,A1)g(D,A2)g(D,A3)g(D,A4)=H(D)−H(D∣A1)=0.083=H(D)−H(D∣A2)=0.324=H(D)−H(D∣A3)=0.420=H(D)−H(D∣A4)=0.363
计算 DDD 关于特征的值的熵
HA1(D)=−(515log2515+515log2515+515log2515)=1.585HA2(D)=−(515log2515+1015log21015)=1.585HA3(D)=−(615log2615+915log2915)=0.971HA4(D)=−(515log2515+615log2615+415log2415)=1.566\begin{aligned} H_{A_1}(D) & = - \left( \frac{5}{15} \log_2 \frac{5}{15} + \frac{5}{15} \log_2 \frac{5}{15} + \frac{5}{15} \log_2 \frac{5}{15} \right) = 1.585 \\ H_{A_2}(D) & = - \left( \frac{5}{15} \log_2 \frac{5}{15} + \frac{10}{15} \log_2 \frac{10}{15} \right) = 1.585\\ H_{A_3}(D) & = - \left( \frac{6}{15} \log_2 \frac{6}{15} + \frac{9}{15} \log_2 \frac{9}{15} \right) = 0.971\\ H_{A_4}(D) & = - \left( \frac{5}{15} \log_2 \frac{5}{15} + \frac{6}{15} \log_2 \frac{6}{15} + \frac{4}{15} \log_2 \frac{4}{15} \right) = 1.566 \end{aligned}HA1(D)HA2(D)HA3(D)HA4(D)=−(155log2155+155log2155+155log2155)=1.585=−(155log2155+1510log21510)=1.585=−(156log2156+159log2159)=0.971=−(155log2155+156log2156+154log2154)=1.566
计算信息增益比
gR(D,A1)=g(D,A1)HA1(D)=0.052gR(D,A2)=g(D,A2)HA2(D)=0.204gR(D,A3)=g(D,A3)HA3(D)=0.433gR(D,A4)=g(D,A4)HA4(D)=0.232\begin{aligned} g_R(D, A_1) & = \frac{g(D, A_1)}{H_{A_1}(D)} = 0.052 \\ g_R(D, A_2) & = \frac{g(D, A_2)}{H_{A_2}(D)} = 0.204 \\ g_R(D, A_3) & = \frac{g(D, A_3)}{H_{A_3}(D)} = 0.433 \\ g_R(D, A_4) & = \frac{g(D, A_4)}{H_{A_4}(D)} = 0.232 \end{aligned}gR(D,A1)gR(D,A2)gR(D,A3)gR(D,A4)=HA1(D)g(D,A1)=0.052=HA2(D)g(D,A2)=0.204=HA3(D)g(D,A3)=0.433=HA4(D)g(D,A4)=0.232
DDD 关于特征 A3A_3A3 的信息增益比最大,所以选择 A3A_3A3 为最优特征
根据 A3A_3A3 对数据集进行分割后,得到了两个新的子集 D1,D2D_1, D_2D1,D2,其中 D1D_1D1 都是同类样本,不需要再进行细分,D2D_2D2 中有 3 个样本类别为“是”,6 个为“否”,需要进行进一步划分
计算 DDD 的经验熵
H(D2)=−(13×log213+23×log223)=0.918H(D_2) = - \left( \frac{1}{3} \times \log_2 \frac{1}{3} + \frac{2}{3} \times \log_2 \frac{2}{3} \right) = 0.918H(D2)=−(31×log231+32×log232)=0.918
计算特征 AiA_iAi 给定条件下 DDD 的条件经验熵
H(D2∣A1)=49H(D2∣A1=1)+29H(D2∣A1=2)+39H(D2∣A1=3)=49(−14log214−34log234)+29×0+39(−23log223−13log213)=0.667H(D2∣A2)=39H(D2∣A2=1)+69H(D2∣A2=2)=0H(D2∣A4)=49H(D2∣A4=1)+49H(D2∣A4=2)+19H(D2∣A4=3)=0.444\begin{aligned} H(D_2 | A_1) & = \frac{4}{9}H(D_2 | A_1 = 1) + \frac{2}{9}H(D_2 | A_1 = 2) + \frac{3}{9}H(D_2 | A_1 = 3) \\ & = \frac{4}{9}\left( -\frac{1}{4} \log_2 \frac{1}{4} -\frac{3}{4} \log_2 \frac{3}{4}\right) + \frac{2}{9}\times 0 + \frac{3}{9}\left( -\frac{2}{3} \log_2 \frac{2}{3} -\frac{1}{3} \log_2 \frac{1}{3}\right) \\ & = 0.667 \\ H(D_2 | A_2) & = \frac{3}{9}H(D_2 | A_2 = 1) + \frac{6}{9}H(D_2 | A_2 = 2) \\ & = 0 \\ H(D_2 | A_4) & = \frac{4}{9}H(D_2 | A_4 = 1) + \frac{4}{9}H(D_2 | A_4 = 2) + \frac{1}{9}H(D_2 | A_4 = 3) \\ & = 0.444 \end{aligned}H(D2∣A1)H(D2∣A2)H(D2∣A4)=94H(D2∣A1=1)+92H(D2∣A1=2)+93H(D2∣A1=3)=94(−41log241−43log243)+92×0+93(−32log232−31log231)=0.667=93H(D2∣A2=1)+96H(D2∣A2=2)=0=94H(D2∣A4=1)+94H(D2∣A4=2)+91H(D2∣A4=3)=0.444
计算信息增益
g(D2,A1)=H(D2)−H(D2∣A1)=0.251g(D2,A2)=H(D2)−H(D2∣A2)=0.918g(D2,A4)=H(D2)−H(D2∣A4)=0.474\begin{aligned} g(D_2, A_1) & = H(D_2) - H(D_2 | A_1) = 0.251 \\ g(D_2, A_2) & = H(D_2) - H(D_2 | A_2) = 0.918 \\ g(D_2, A_4) & = H(D_2) - H(D_2 | A_4) = 0.474 \\ \end{aligned}g(D2,A1)g(D2,A2)g(D2,A4)=H(D2)−H(D2∣A1)=0.251=H(D2)−H(D2∣A2)=0.918=H(D2)−H(D2∣A4)=0.474
计算 D2D_2D2 关于特征的值的熵
HA1(D2)=−(49log249+29log229+39log239)=1.530HA2(D2)=−(39log239+69log269)=0.918HA4(D2)=−(19log219+49log249+49log249)=1.392\begin{aligned} H_{A_1}(D_2) & = - \left( \frac{4}{9} \log_2 \frac{4}{9} + \frac{2}{9} \log_2 \frac{2}{9} + \frac{3}{9} \log_2 \frac{3}{9} \right) = 1.530 \\ H_{A_2}(D_2) & = - \left( \frac{3}{9} \log_2 \frac{3}{9} + \frac{6}{9} \log_2 \frac{6}{9} \right) = 0.918\\ H_{A_4}(D_2) & = - \left( \frac{1}{9} \log_2 \frac{1}{9} + \frac{4}{9} \log_2 \frac{4}{9} + \frac{4}{9} \log_2 \frac{4}{9} \right) = 1.392 \end{aligned}HA1(D2)HA2(D2)HA4(D2)=−(94log294+92log292+93log293)=1.530=−(93log293+96log296)=0.918=−(91log291+94log294+94log294)=1.392
计算信息增益比
gR(D2,A1)=g(D2,A1)HA1(D2)=0.164gR(D2,A2)=g(D2,A2)HA2(D2)=1.000gR(D2,A4)=g(D2,A4)HA4(D2)=0.341\begin{aligned} g_R(D_2, A_1) & = \frac{g(D_2, A_1)}{H_{A_1}(D_2)} = 0.164 \\ g_R(D_2, A_2) & = \frac{g(D_2, A_2)}{H_{A_2}(D_2)} = 1.000 \\ g_R(D_2, A_4) & = \frac{g(D_2, A_4)}{H_{A_4}(D_2)} = 0.341 \end{aligned}gR(D2,A1)gR(D2,A2)gR(D2,A4)=HA1(D2)g(D2,A1)=0.164=HA2(D2)g(D2,A2)=1.000=HA4(D2)g(D2,A4)=0.341
D2D_2D2 关于特征 A2A_2A2 的信息增益比最大,所以选择 A2A_2A2 为最优特征
此时所有子集的样本点都是同一类,结束
剪枝
记前面生成的决策树为 T0T_0T0 ,因为D1,D21,D22D_1, D_{21}, D_{22}D1,D21,D22 中的样本点都是同一类,所以 H(D1),H(D21),H(D22)H(D_1), H(D_{21}), H(D_{22})H(D1),H(D21),H(D22)都是 0 ,叶结点个数 ∣T0∣=3|T_0| = 3∣T0∣=3,易求得 Cα(T0)=3αC_\alpha (T_0) = 3\alphaCα(T0)=3α
若在 D2D_2D2 处进行剪枝,记剪枝后的树为 T1T_1T1,对于叶结点 D1,D2D_1, D_2D1,D2,知道 H(D1)=0,H(D2)=0.918H(D_1) = 0, H(D_2) = 0.918H(D1)=0,H(D2)=0.918,于是
Cα(T1)=6H(D1)+9H(D2)+2α=8.262+2αC_\alpha(T_1) = 6\ H(D_1) + 9\ H(D_2) + 2\alpha = 8.262 + 2\alphaCα(T1)=6 H(D1)+9 H(D2)+2α=8.262+2α
故当 3α≥8.262+2α3\alpha \ge 8.262 + 2\alpha3α≥8.262+2α,即 α≥8.262\alpha \ge 8.262α≥8.262 时应该剪枝(取等时根据奥卡姆剃刀原则选择结点更少的)
若继续对 T1T_1T1 进行剪枝,记剪枝后的树为 T2T_2T2, 即以根结点为单结点的树,H(D)=0.971H(D) = 0.971H(D)=0.971,Cα(T2)=15H(D)+α=14.565+αC_\alpha (T_2) = 15 H(D) + \alpha = 14.565 + \alphaCα(T2)=15H(D)+α=14.565+α,故当 8.262+2α≥14.565+α8.262 + 2\alpha \ge 14.565 + \alpha8.262+2α≥14.565+α,即 α≥6.303\alpha \ge 6.303α≥6.303 时应当剪枝
综上当 0≤α<6.3030 \le \alpha \lt 6.3030≤α<6.303 时,不需要剪枝,最终子树为整体树 T0T_0T0,当 α≥6.303\alpha \ge 6.303α≥6.303 时修剪后的子树为以根结点为单结点的树 T2T_2T2
1.8.1.3 CART
计算特征关于 DDD 的基尼指数
Gini(D,A1=1)=515(1−(25)2−(35)2)+1015(1−(310)2−(710)2)=0.44Gini(D,A1=2)=515(1−(25)2−(35)2)+1015(1−(410)2−(610)2)=0.48Gini(D,A1=3)=515(1−(45)2−(15)2)+1015(1−(510)2−(510)2)=0.44Gini(D,A2=1)=515×0+1015(1−(410)2−(610)2)=0.32,因为A2是二值特征,所以只求一个就可以Gini(D,A3=1)=615×0+915(1−(39)2−(69)2)=0.27Gini(D,A4=1)=415×0+1115(1−(511)2−(611)2)=0.36Gini(D,A4=2)=615(1−(46)2−(26)2)+915(1−(59)2−(49)2)=0.47Gini(D,A4=3)=515(1−(15)2−(45)2)+1015(1−(810)2−(210)2)=0.32\begin{aligned} Gini(D, A_1 = 1) = \frac{5}{15}\left( 1 - {(\frac{2}{5})}^2 - {(\frac{3}{5})}^2\right) + \frac{10}{15}\left( 1 - {(\frac{3}{10})}^2 - {(\frac{7}{10})}^2\right) = 0.44 \\ Gini(D, A_1 = 2) = \frac{5}{15}\left( 1 - {(\frac{2}{5})}^2 - {(\frac{3}{5})}^2\right) + \frac{10}{15}\left( 1 - {(\frac{4}{10})}^2 - {(\frac{6}{10})}^2\right) = 0.48 \\ Gini(D, A_1 = 3) = \frac{5}{15}\left( 1 - {(\frac{4}{5})}^2 - {(\frac{1}{5})}^2\right) + \frac{10}{15}\left( 1 - {(\frac{5}{10})}^2 - {(\frac{5}{10})}^2\right) = 0.44 \\ Gini(D, A_2 = 1) = \frac{5}{15} \times 0 + \frac{10}{15}\left( 1 - {(\frac{4}{10})}^2 - {(\frac{6}{10})}^2\right) = 0.32 , \quad \text{因为}A_2\text{是二值特征,所以只求一个就可以}\\ Gini(D, A_3 = 1) = \frac{6}{15} \times 0 + \frac{9}{15}\left( 1 - {(\frac{3}{9})}^2 - {(\frac{6}{9})}^2\right) = 0.27 \\ Gini(D, A_4 = 1) = \frac{4}{15}\times 0 + \frac{11}{15}\left( 1 - {(\frac{5}{11})}^2 - {(\frac{6}{11})}^2\right) = 0.36 \\ Gini(D, A_4 = 2) = \frac{6}{15}\left( 1 - {(\frac{4}{6})}^2 - {(\frac{2}{6})}^2\right) + \frac{9}{15}\left( 1 - {(\frac{5}{9})}^2 - {(\frac{4}{9})}^2\right) = 0.47 \\ Gini(D, A_4 = 3) = \frac{5}{15}\left( 1 - {(\frac{1}{5})}^2 - {(\frac{4}{5})}^2\right) + \frac{10}{15}\left( 1 - {(\frac{8}{10})}^2 - {(\frac{2}{10})}^2\right) = 0.32 \\ \end{aligned}Gini(D,A1=1)=155(1−(52)2−(53)2)+1510(1−(103)2−(107)2)=0.44Gini(D,A1=2)=155(1−(52)2−(53)2)+1510(1−(104)2−(106)2)=0.48Gini(D,A1=3)=155(1−(54)2−(51)2)+1510(1−(105)2−(105)2)=0.44Gini(D,A2=1)=155×0+1510(1−(104)2−(106)2)=0.32,因为A2是二值特征,所以只求一个就可以Gini(D,A3=1)=156×0+159(1−(93)2−(96)2)=0.27Gini(D,A4=1)=154×0+1511(1−(115)2−(116)2)=0.36Gini(D,A4=2)=156(1−(64)2−(62)2)+159(1−(95)2−(94)2)=0.47Gini(D,A4=3)=155(1−(51)2−(54)2)+1510(1−(108)2−(102)2)=0.32
其中最小的是 Gini(D,A3=1)=0.27Gini(D, A_3 = 1) = 0.27Gini(D,A3=1)=0.27,故选择 A3A_3A3 为最优特征,A3=1A_3 = 1A3=1 为最优切分点
计算特征关于 D2D_2D2 的基尼指数
Gini(D2,A1=1)=49(1−(14)2−(34)2)+59(1−(25)2−(35)2)=0.60Gini(D2,A1=2)=29×0+79(1−(37)2−(47)2)=0.38Gini(D2,A1=3)=39(1−(23)2−(13)2)+69(1−(16)2−(56)2)=0.33Gini(D2,A2=1)=39×0+69×0=0.0Gini(D2,A4=1)=19×0+89(1−(28)2−(68)2)=0.33Gini(D2,A4=2)=49(1−(24)2−(24)2)+59(1−(15)2−(45)2)=0.40Gini(D2,A4=3)=49×0+59(1−(35)2−(25)2)=0.27\begin{aligned} Gini(D_2, A_1 = 1) = \frac{4}{9}\left( 1 - {(\frac{1}{4})}^2 - {(\frac{3}{4})}^2\right) + \frac{5}{9}\left( 1 - {(\frac{2}{5})}^2 - {(\frac{3}{5})}^2\right) = 0.60 \\ Gini(D_2, A_1 = 2) = \frac{2}{9}\times 0 + \frac{7}{9}\left( 1 - {(\frac{3}{7})}^2 - {(\frac{4}{7})}^2\right) = 0.38 \\ Gini(D_2, A_1 = 3) = \frac{3}{9}\left( 1 - {(\frac{2}{3})}^2 - {(\frac{1}{3})}^2\right) + \frac{6}{9}\left( 1 - {(\frac{1}{6})}^2 - {(\frac{5}{6})}^2\right) = 0.33 \\ Gini(D_2, A_2 = 1) = \frac{3}{9} \times 0 + \frac{6}{9}\times 0 = 0.0 \\ Gini(D_2, A_4 = 1) = \frac{1}{9}\times 0 + \frac{8}{9}\left( 1 - {(\frac{2}{8})}^2 - {(\frac{6}{8})}^2\right) = 0.33 \\ Gini(D_2, A_4 = 2) = \frac{4}{9}\left( 1 - {(\frac{2}{4})}^2 - {(\frac{2}{4})}^2\right) + \frac{5}{9}\left( 1 - {(\frac{1}{5})}^2 - {(\frac{4}{5})}^2\right) = 0.40 \\ Gini(D_2, A_4 = 3) = \frac{4}{9}\times 0 + \frac{5}{9}\left( 1 - {(\frac{3}{5})}^2 - {(\frac{2}{5})}^2\right) = 0.27 \\ \end{aligned}Gini(D2,A1=1)=94(1−(41)2−(43)2)+95(1−(52)2−(53)2)=0.60Gini(D2,A1=2)=92×0+97(1−(73)2−(74)2)=0.38Gini(D2,A1=3)=93(1−(32)2−(31)2)+96(1−(61)2−(65)2)=0.33Gini(D2,A2=1)=93×0+96×0=0.0Gini(D2,A4=1)=91×0+98(1−(82)2−(86)2)=0.33Gini(D2,A4=2)=94(1−(42)2−(42)2)+95(1−(51)2−(54)2)=0.40Gini(D2,A4=3)=94×0+95(1−(53)2−(52)2)=0.27
其中最小的是 Gini(D2,A2=1)=0Gini(D_2, A_2 = 1) = 0Gini(D2,A2=1)=0,故选择 A2A_2A2 为最优特征,A2=1A_2 = 1A2=1 为最优切分点
此时所有子集的样本点都是同一类,结束
剪枝
初始树 T=T0T = T_0T=T0,对内部结点 D2D_2D2 计算基尼指数
Gini(D2)=1−(39)2−(69)2=0.44Gini(D_2) = 1 - {(\frac{3}{9})}^2 - {(\frac{6}{9})}^2 = 0.44Gini(D2)=1−(93)2−(96)2=0.44
于是
C(D2)=Gini(D2)=0.44C(D_2) = Gini(D_2) = 0.44C(D2)=Gini(D2)=0.44
而以 D2D_2D2 为结点的子树已经完全分类,不确定性为0,所以 CTD2=0C_{T_{D_2}} = 0CTD2=0。又 ∣TD2∣=2|T_{D_2}| = 2∣TD2∣=2。于是
α(D2)=C(D2)−CTD2∣TD2∣−1=0.44\alpha(D_2) = \frac{C(D_2) - C_{T_{D_2}}}{|T_{D_2}| - 1} = 0.44α(D2)=∣TD2∣−1C(D2)−CTD2=0.44
α=min(+∞,α(D2))=α(D2)=0.44\alpha = \min (+\infty, \alpha(D_2)) = \alpha(D_2) = 0.44α=min(+∞,α(D2))=α(D2)=0.44
k=k+1=1,α1=α=0.44,T1=Tk = k + 1 = 1, \alpha_1 = \alpha = 0.44, T_1 = Tk=k+1=1,α1=α=0.44,T1=T,此时满足停止条件(T1T_1T1 为由根结点和两个叶结点构成的树),令 T1=TnT_1 = T_nT1=Tn,得到子树序列 {T0,T1}\{T_0, T_1\}{T0,T1}(T0T_0T0 为区间 [0,0.44)[0, 0.44)[0,0.44) 的最优子树,T1T_1T1 为区间 [0.44,+∞)[0.44, +\infty)[0.44,+∞) 对应的最优子树)。后续的工作需要借助验证集。
1.8.2 CART回归
利用如下训练数据,用平方损失准则生成一个二叉回归树
xix_ixi | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
yiy_iyi | 4.50 | 4.75 | 4.91 | 5.34 | 5.80 | 7.05 | 7.90 | 8.23 | 8.70 | 9.00 |
解 因为数据只有一个特征,所以只需要寻找最优切分点,令
g(s)=minc1∑xi≤s(yi−c1)2+minc2∑xi≤s(yi−c2)2g(s) = \mathop{\min}_{c_1} \sum_{x_i \le s}{(y_i - c_1)}^2 + \mathop{\min}_{c_2} \sum_{x_i \le s}{(y_i - c_2)}^2g(s)=minc1xi≤s∑(yi−c1)2+minc2xi≤s∑(yi−c2)2
对该组数据,自然想到一组切分点 {1.5,2.5,⋯ ,9.5}\{ 1.5, 2.5, \cdots, 9.5\}{1.5,2.5,⋯,9.5} (当然还有无数种其它的选择,不过没什么区别。比如选择 1 或 1.9999 作为切分点效果是一样的)。则
g(1.5)=minc1∑xi≤1.5(yi−c1)2+minc2∑xi>1.5(yi−c2)2=∑xi≤1.5(yi−yiˉ{xi≤1.5})2+∑xi>1.5(yi−yiˉ{xi>1.5})2=0+22.650=22.65g(2.5)=0.031+17.671=17.70g(3.5)=0.085+12.108=12.19g(4.5)=0.374+7.005=7.38g(5.5)=1.058+2.300=3.36g(6.5)=4.358+0.716=5.07g(7.5)=9.751+0.301=10.05g(8.5)=15.132+0.045=15.18g(9.5)=21.330+0=21.33\begin{aligned} g(1.5) & = \mathop{\min}_{c_1} \sum_{x_i \le 1.5}{(y_i - c_1)}^2 + \mathop{\min}_{c_2} \sum_{x_i \gt 1.5}{(y_i - c_2)}^2 \\ & = \sum_{x_i \le 1.5}{(y_i - \bar{y_i}_{\{x_i \le 1.5\}})}^2 + \sum_{x_i \gt 1.5}{(y_i - \bar{y_i}_{\{x_i \gt 1.5\}})}^2 \\ & = 0 + 22.650 \\ & = 22.65 \\ g(2.5) & = 0.031 + 17.671 = 17.70 \\ g(3.5) & = 0.085 + 12.108 = 12.19 \\ g(4.5) & = 0.374 + 7.005 = 7.38 \\ g(5.5) & = 1.058 + 2.300 = \mathbf{3.36} \\ g(6.5) & = 4.358 + 0.716 = 5.07 \\ g(7.5) & = 9.751 + 0.301 = 10.05 \\ g(8.5) & = 15.132 + 0.045 = 15.18 \\ g(9.5) & = 21.330 + 0 = 21.33 \end{aligned}g(1.5)g(2.5)g(3.5)g(4.5)g(5.5)g(6.5)g(7.5)g(8.5)g(9.5)=minc1xi≤1.5∑(yi−c1)2+minc2xi>1.5∑(yi−c2)2=xi≤1.5∑(yi−yiˉ{xi≤1.5})2+xi>1.5∑(yi−yiˉ{xi>1.5})2=0+22.650=22.65=0.031+17.671=17.70=0.085+12.108=12.19=0.374+7.005=7.38=1.058+2.300=3.36=4.358+0.716=5.07=9.751+0.301=10.05=15.132+0.045=15.18=21.330+0=21.33
其中 g(5.5)g(5.5)g(5.5) 最小,因此5.5作为最优切分点,若此时达到停止条件,输出每个结点中样本的均值
c1^=∑xi≤5.5yi=5.06,c2^=∑xi>5.5yi=8.18\hat{c_1} = \sum{x_i \le 5.5} y_i = 5.06, \ \hat{c_2} = \sum{x_i \gt 5.5} y_i = 8.18c1^=∑xi≤5.5yi=5.06, c2^=∑xi>5.5yi=8.18
若未达成停止条件继续对 D1,D2D_1, D_2D1,D2 进行划分,对 D1D_1D1 求 g(s)g(s)g(s)
g(1.5)=0+0.666=0.67g(2.5)=0.031+0.396=0.43g(3.5)=0.085+0.106=0.19g(4.5)=0.374+0=0.37\begin{aligned} g(1.5) & = 0 + 0.666 = 0.67 \\ g(2.5) & = 0.031 + 0.396 = 0.43 \\ g(3.5) & = 0.085 + 0.106 = \mathbf{0.19} \\ g(4.5) & = 0.374 + 0 = 0.37 \end{aligned}g(1.5)g(2.5)g(3.5)g(4.5)=0+0.666=0.67=0.031+0.396=0.43=0.085+0.106=0.19=0.374+0=0.37
其中 g(3.5)g(3.5)g(3.5) 最小,故 3.5 为 D1D_1D1 的最优切分点,接着对 D2D_2D2 求 g(s)g(s)g(s)
g(6.5)=0+0.716=0.72g(7.5)=0.361+0.301=0.66g(8.5)=0.741+0.045=0.79g(9.5)=1.452+0=1.45\begin{aligned} g(6.5) & = 0 + 0.716 = 0.72 \\ g(7.5) & = 0.361 + 0.301 = \mathbf{0.66} \\ g(8.5) & = 0.741 + 0.045 = 0.79 \\ g(9.5) & = 1.452 + 0 = 1.45 \end{aligned}g(6.5)g(7.5)g(8.5)g(9.5)=0+0.716=0.72=0.361+0.301=0.66=0.741+0.045=0.79=1.452+0=1.45
其中 g(7.5)g(7.5)g(7.5) 最小,故 7.5 为 D2D_2D2 的最优切分点。若此时达到停止条件,输出每个结点中样本的均值
c11^=∑xi≤3.5yi=4.72,c12^=∑3.5≤xi>5.5yi=5.57\hat{c_11} = \sum{x_i \le 3.5} y_i = 4.72, \ \hat{c_12} = \sum{3.5 \le x_i \gt 5.5} y_i = 5.57c11^=∑xi≤3.5yi=4.72, c12^=∑3.5≤xi>5.5yi=5.57
c21^=∑5.5<xi≤7.5yi=7.48,c22^=∑7.5≤xiyi=8.64\hat{c_21} = \sum{5.5 \lt x_i \le 7.5} y_i = 7.48, \ \hat{c_22} = \sum{7.5 \le x_i} y_i = 8.64c21^=∑5.5<xi≤7.5yi=7.48, c22^=∑7.5≤xiyi=8.64
当然还可以继续向下划分,这里不再计算
1.9 总结
1.9.1 决策树的优点
便于理解和解释。树的结构可以可视化出来。
训练需要的数据少。其他机器学习模型通常需要数据规范化,比如构建虚拟变量和移除缺失值,不过请注意,这种模型不支持缺失值。
由于训练决策树的数据点的数量导致了决策树的使用开销呈指数分布(训练树模型的时间复杂度是参与训练数据点的对数值)。
能够处理数值型数据和分类数据。其他的技术通常只能用来专门分析某一种变量类型的数据集。
能够处理多路输出的问题。
使用白盒模型。如果某种给定的情况在该模型中是可以观察的,那么就可以轻易的通过布尔逻辑来解释这种情况。相比之下,在黑盒模型中的结果就是很难说明清楚地。
可以通过数值统计测试来验证该模型。这对事解释验证该模型的可靠性成为可能。
即使该模型假设的结果与真实模型所提供的数据有些违反,其表现依旧良好。
1.9.2 决策树的缺点
决策树模型容易产生一个过于复杂的模型,这样的模型对数据的泛化性能会很差,即所谓的过拟合。一些策略像剪枝、设置叶结点所需的最小样本数或设置树的最大深度是避免出现该问题的有效方法。
决策树可能是不稳定的,因为数据中的微小变化可能会导致完全不同的树生成。这个问题可以通过决策树的集成来得到解决,比如随机森林。
在多方面性能最优和简单化概念的要求下,学习一棵最优决策树通常是一个NP难问题。因此,实际的决策树学习算法是基于启发式算法,例如在每个结点进行“局部最优”决策的贪心算法。这样的算法不能保证返回全局最优决策树。这个问题可以通过集成学习来训练多棵决策树来解决,一般通过对特征和样本有放回的随机采样来生成。
有些概念很难被决策树学习到,因为决策树很难清楚的表述这些概念。例如XOR(异或),奇偶或者复用器的问题。当然任何线性分类模型都无法解决异或问题。
如果某些类在问题中占主导地位会使得创建的决策树有偏差。因此,我们建议在拟合前先对数据集进行平衡。
2 算法实现
2.1 基础数据结构的python实现
import numpy as np
import pandas as pd
from functools import reducedata = pd.DataFrame({'年龄': ['青年','青年','青年','青年','青年','中年','中年','中年','中年','中年','老年','老年','老年','老年','老年'], '有工作': ['否','否','是','是','否','否','否','是','否','否','否','否','是','是','否'], '有自己的房子': ['否','否','否','是','否','否','否','是','是','是','是','是','否','否','否'], '信贷情况': ['一般','好','好','一般','一般','一般','好','好','非常好','非常好','非常好','好','好','非常好','一般'], 'label': ['否','否','是','是','否','否','否','是','是','是','是','是','是','是','否']}, index = range(1, 16))data
class Node:'''自定义结点类,用于保存实例点序号和结点标签'''def __init__(self, data, attr = '根结点'):self.data = dataself.sample = list(data.index)self.label = max(data.label)self.attr = attr # 保存生成结点时所选择的特征和特征值def get_data(self):return self.datadef get_sample(self):return self.sampledef get_label(self):return self.labeldef get_attr(self):return self.attrdef __str__(self):return '该结点保存的实例序号为:'+str(self.sample)+'\n标签为:'+str(self.label)class Tree:'''普通树类,适用 ID3 和 C4.5 算法'''def __init__(self, node, n):'''para data: Node类'''self.root = nodeself.n = n # 最大度(暂定手动设置,当数据量较小时观察数据可以获取)for i in range(n): # 子树setattr(self, 'subtree_'+str(i), None)def is_empty(self):return self.root == Nonedef set_root(self, node):self.root = nodedef get_root(self):return self.rootdef set_subtree(self, node, i):'''设置第i个子树'''if getattr(self, 'subtree_'+str(i)) == None:setattr(self, 'subtree_'+str(i), Tree(node, self.n))else:temptree = Tree(node, self.n)temptree.subtree_0 = getattr(self, 'subtree_'+str(i))setattr(self, 'subtree_'+str(i), temptree)def get_subtree(self, i):'''获取第i个子树'''return getattr(self, 'subtree_'+str(i))def get_allsub(self):'''获取全部子树'''return [getattr(self, 'subtree_'+str(i)) for i in range(self.n)]class Tree2:'''二叉树类,适用 CART树 算法'''def __init__(self, node):self.root = nodeself.left = Noneself.right = Nonedef is_empty(self):return self.root == Nonedef set_root(self, node):self.root = nodedef get_root(self):return self.rootdef set_left(self, node):if self.left == None:self.lefe = Tree2(node)else:temptree = Tree2(node)temptree.left = self.leftself.left = temptreedef set_right(self, node):if self.right == None:self.right = Tree2(node)else:temptree = Tree2(node)temptree.right = self.rightself.right = temptreedef get_left(self):return self.leftdef get_right(self):return self.right
nod = Node(data)
print(nod)
该结点保存的实例序号为:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
标签为:是
t = Tree(nod, 3)
t.get_root()
<main.Node at 0x1af45d26f98>
2.2 数据不确定性计算的python实现
2.2.1经验熵
H(X)=−∑i=1npilogpiH(X) = - \sum_{i = 1}^{n} p_i \log p_iH(X)=−i=1∑npilogpi
def Ent(data, base = 2):'''经验熵计算para data: 一维数据para base: 计算对数时的底数,默认为 2,可以选 np.e 或者 10return [float]: 经验熵结果'''if base == 2:log = np.log2elif base == np.e:log = np.logelif base == 10:log = np.log10else:raise ValueError('不是一个可使用的底数!')labeldict = {}size = len(data)for sample in data:labeldict[sample] = labeldict.get(sample, 0) + 1/sizereturn reduce((lambda x, y: x + y), map((lambda x: - x * log(x)), labeldict.values()))
Ent(data.label, 2)
0.9709505944546687
2.2.2 条件熵
H(Y∣X)=∑i=1npiH(Y∣X=xi)H(Y|X) = \sum_{i = 1}^{n} p_i H(Y|X = x_i)H(Y∣X)=i=1∑npiH(Y∣X=xi)
def cEnt(data, base = 2):'''条件经验熵计算para data: 数据para base: 计算对数时的底数,默认为 2,可以选 np.e 或者 10return dict([attr: [float]]): 条件经验熵结果'''if base == 2:log = np.log2elif base == np.e:log = np.logelif base == 10:log = np.log10else:raise ValueError('不是一个可使用的底数!')X = data.iloc[:, :-1]ent = {}size = data.shape[0]for attr in X.columns:ent[attr] = 0labeldict = {}for v in X[attr]:if v not in labeldict:labeldict[v] = [1/size, 0]else:labeldict[v][0] += 1/sizefor v in labeldict:labeldict[v][1] += Ent(data.loc[(data[attr]==v), 'label'], base)ent[attr] += labeldict[v][0] * labeldict[v][1]return ent
cEnt(data)
{‘年龄’: 0.8879430945988998,
‘有工作’: 0.6473003963031123,
‘有自己的房子’: 0.5509775004326938,
‘信贷情况’: 0.6079610319175832}
2.2.3 信息增益
g(D,A)=H(D)−H(D∣A)g(D, A) = H(D) - H(D|A)g(D,A)=H(D)−H(D∣A)
def info_gain(data, base = 2):'''信息增益计算para data: 数据para base: 计算对数时的底数,默认为 2,可以选 np.e 或者 10return dict([attr: [float]]): 信息增益结果'''ent = Ent(data.label, base)cent = cEnt(data, base)gain = {}for attr in cent:gain[attr] = ent - cent[attr]return gain
info_gain(data)
{‘年龄’: 0.08300749985576894,
‘有工作’: 0.3236501981515564,
‘有自己的房子’: 0.4199730940219749,
‘信贷情况’: 0.3629895625370855}
2.2.4 特征的熵
HA(D)=−∑j=1S∣Di∣∣D∣log2∣Di∣∣D∣H_A (D) = - \sum_{j = 1}^{S} \frac{|D_i|}{|D|} \log_2 \frac{|D_i|}{|D|}HA(D)=−j=1∑S∣D∣∣Di∣log2∣D∣∣Di∣
def attr_Ent(data, base = 2):'''计算特征的熵para data: 数据para base: 计算对数时的底数,默认为 2,可以选 np.e 或者 10return dict([attr: [float]]): 数据关于特征的经验熵结果'''X = data.iloc[:, :-1]attr_ent = {}for attr in X.columns:attr_ent[attr] = Ent(X[attr], base)return attr_ent
attr_Ent(data)
{‘年龄’: 1.584962500721156,
‘有工作’: 0.9182958340544896,
‘有自己的房子’: 0.9709505944546687,
‘信贷情况’: 1.565596230357602}
2.2.5 信息增益比
gR(D,A)=g(D,A)HA(D)g_R (D, A) = \frac{g(D, A)}{H_A (D)}gR(D,A)=HA(D)g(D,A)
def info_gain_r(data, base = 2):'''信息增益比计算para data: 数据para base: 计算对数时的底数,默认为 2,可以选 np.e 或者 10return dict([attr: [float]]): 信息增益比结果'''gain = info_gain(data, base)attr_ent = attr_Ent(data, base)gr = {}for attr in gain:gr[attr] = gain[attr] / attr_ent[attr]return gr
info_gain_r(data)
{‘年龄’: 0.05237190142858309,
‘有工作’: 0.35244654952050203,
‘有自己的房子’: 0.43253806776631254,
‘信贷情况’: 0.23185388128724227}
2.2.6 基尼指数
Gini(p)=∑k=1Kpk(1−pk)=1−∑k=1Kpk2Gini(p) = \sum_{k = 1}^{K} p_k (1 - p_k) = 1 - \sum_{k = 1}^{K}p_k^2Gini(p)=k=1∑Kpk(1−pk)=1−k=1∑Kpk2
Gini(D,A)=∣D1∣∣D∣Gini(D1)+∣D2∣∣D∣Gini(D2)Gini(D, A) = \frac{|D_1|}{|D|} Gini(D_1) + \frac{|D_2|}{|D|} Gini(D_2)Gini(D,A)=∣D∣∣D1∣Gini(D1)+∣D∣∣D2∣Gini(D2)
def Gini(data):'''计算基尼指数para data: 一维数据return [float]: 基尼指数结果'''labeldict = {}size = len(data)for v in data:labeldict[v] = labeldict.get(v, 0) + 1/sizereturn 1 - reduce((lambda x, y: x + y), map((lambda x: x**2), labeldict.values()))
Gini(data.label)
0.48
def Gini_attr(data):'''计算特征的基尼指数para data: 数据return dict(['attr': ['attr_value', float]]): 各特征的基尼指数'''X = data.iloc[:, :-1]gini = {}size = X.shape[0]for attr in X.columns:attrdict = {}for v in X[attr]:attrdict[v] = attrdict.get(v, 0) + 1/sizefor v in attrdict:gini[(attr, v)] = attrdict[v]*Gini(data.loc[(data[attr]==v), 'label'])+(1 - attrdict[v])*Gini(data.loc[(data[attr]!=v), 'label'])return gini
Gini_attr(data)
{(‘年龄’, ‘青年’): 0.44000000000000006,
(‘年龄’, ‘中年’): 0.48,
(‘年龄’, ‘老年’): 0.43999999999999995,
(‘有工作’, ‘否’): 0.31999999999999995,
(‘有工作’, ‘是’): 0.32,
(‘有自己的房子’, ‘否’): 0.2666666666666668,
(‘有自己的房子’, ‘是’): 0.26666666666666683,
(‘信贷情况’, ‘一般’): 0.32,
(‘信贷情况’, ‘好’): 0.4740740740740741,
(‘信贷情况’, ‘非常好’): 0.3636363636363636}
2.3 ID3的python实现
class ID3:def __init__(self, e = 0.1):'''para e: 信息增益阈值'''self.e = edef fit(self, data, attr = '根结点', printlog = False):# 生成结点if (printlog == True) & (attr == '根结点'):print('{0:-^70}'.format('树的生成'))nod = Node(data, attr)t = Tree(nod, 3)if printlog == True:print('生成结点:%s,\n包含实例点:%s,\n结点的标签为:%s' %(nod.attr, nod.sample, nod.label))# 特征选择gain = info_gain(data)max_gain = gain.get(max(gain))if printlog == True:print('当前信息增益为:%.2f' %max_gain, '\n', '-'*30)if max_gain < self.e:return telse:elec_attr = max(gain)if printlog == True:print('选择特征 -> ', elec_attr)for i, v in enumerate(data[elec_attr].unique()):dat = data.loc[data[elec_attr]==v].copy() # 不用copy()的话会报错SettingWithCopyWarningdat.drop([elec_attr], axis = 1, inplace = True)tdict = {elec_attr: v}t.set_subtree(self.fit(dat, tdict, printlog), i)return
id3 = ID3()
id3.fit(data, printlog=True)
---------------------------------树的生成---------------------------------
生成结点:根结点,
包含实例点:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
结点的标签为:是
当前信息增益为:0.42
------------------------------
选择特征 -> 有自己的房子
生成结点:{‘有自己的房子’: ‘否’},
包含实例点:[1, 2, 3, 5, 6, 7, 13, 14, 15],
结点的标签为:是
当前信息增益为:0.92
------------------------------
选择特征 -> 有工作
生成结点:{‘有工作’: ‘否’},
包含实例点:[1, 2, 5, 6, 7, 15],
结点的标签为:否
当前信息增益为:0.00
------------------------------
生成结点:{‘有工作’: ‘是’},
包含实例点:[3, 13, 14],
结点的标签为:是
当前信息增益为:-0.00
------------------------------
生成结点:{‘有自己的房子’: ‘是’},
包含实例点:[4, 8, 9, 10, 11, 12],
结点的标签为:是
当前信息增益为:0.00
------------------------------
从记录来看算法和我们之前在纸上计算的结果是一致的,只要信息增益很小就说明该结点中的实例点都是同一类的,也可以尝试在代码中进行补充。
由于剪枝涉及到的树的遍历太麻烦啦(*/ω\*),以后有时间再尝试实现。另外C4.5和ID3只有特征选择标准不同,修改一下就可以;CART分类树涉及到特征的二值化处理,回归树涉及到切分点的选择,算是不同于ID3的地方。
3 sklearn分类决策树
分类决策树的函数为 sklearn.tree.DecisionTreeClassifier()
3.1 参数列表
参数名 | 参数类型 | 参数说明 |
---|---|---|
criterion | string, optional (default=”gini”) | 特征选择标准:“gini”代表基尼指数;“entropy”代表信息增益。如非特殊需要使用“gini”就可以了,效率也更高(没有对数运算) |
splitter | string, optional (default=”best”) | 特征和切分点:“best”代表最优切分,当数据量不是非常大时选择该参数值即可;“random” 表示在前几个最优切分点中随机选择一个,一般数据量非常大时使用 |
max_depth | int or None, optional (default=None) | 树的最大深度:None表示所有叶结点的特征选择标准达到阈值或者叶结点的样本数小于最小样本数(min_samples_split) |
min_samples_split | int, float, optional (default=2) | 对一个结点进行划分的最小样本数:如果当前结点中的样本数大于该参数,那么继续进行划分。如果传入float型参数值,那么该参数乘以样本数量的向上取整后的值作为最小样本数 |
min_samples_leaf | int, float, optional (default=1) | 叶结点需要的最小样本数:如果一个叶结点的样本数小于该参数,那么会对其父结点进行剪枝。该参数的意义可能是平滑模型,尤其在做回归任务时。如果传入float型参数值,那么该参数乘以样本数量的向上取整后的值作为最小样本数 |
min_weight_fraction_leaf | float, optional (default=0.) | 叶结点所有样本权重和的最小值:当一个叶结点的样本权重和小于该参数时,对其父结点进行剪枝。一般当数据缺失值较多,或者类别的分布严重不平衡时才使用样本权重。默认等权重 |
max_features | int, float, string or None, optional (default=None) | 寻找最优特征时考虑的最大特征数量:若为float,用该参数乘以数据特征数的向下取整传入;若为“auto”或“sqrt”, 那么传入数据特征数的平方根;若为“log2”, 那么传入数据特征数的以2为底的对数;默认使用全部特征 |
random_state | int, RandomState instance or None, optional (default=None) | 随机种子 |
max_leaf_nodes | int or None, optional (default=None) | 最大叶子结点树:默认不进行限制,当特征数很多时可以通过交叉验证确定合适的参数值 |
min_impurity_decrease | float, optional (default=0.) | 不确定性降低的最小值:当不确定性(基尼系数,信息增益,均方差,绝对差)的下降小于该参数时算法停止 |
class_weight | dict, list of dicts, “balanced” or None, default=None | 类别权重:主要是为了防止训练集某些类别的样本过多,导致训练的决策树过于偏向这些类别,默认等权重。对于多类别数据,自定义权重应传入如下形式[{0: 1, 1: 1}, {0: 1, 1: 5}, {0: 1, 1: 1}, {0: 1, 1: 1}] ,而不是 [{1:1}, {2:5}, {3:1}, {4:1}]形式。“balanced”会根据类别的频数反比自动调整权重:样本数/(类别数*该类别的样本数) |
presort | bool, optional (default=False) | 是否对数据进行提前排序:默认不进行预排序。对于大的数据集来说,设置该参数可能降低训练速度,但是对于小数据集或有深度限制的树来说,预排序可能提高训练速度。 |
可以发现绝大部分参数都是为了防止决策树的过拟合设置的
3.2 属性列表
属性名 | 属性类型 | 属性说明 |
---|---|---|
classes_ | array of shape = [n_classes] or a list of such arrays | 类别 |
feature_importances_ | array of shape = [n_features] | 特征重要性 |
max_features_ | int | 最大特征数 |
n_classes_ | int or list | 类别数量 |
n_features_ | int | 特征数量 |
n_outputs_ | int | 输出数量(多输出决策树) |
tree_ | Tree object | 树结构 |
3.3 模型调参注意事项:
当样本少数量但是样本特征非常多的时候,决策树很容易过拟合,一般来说,样本数比特征数多一些会比较容易建立健壮的模型
如果样本数量少但是样本特征非常多,在拟合决策树模型前,推荐先做维度规约,比如主成分分析(PCA),特征选择(Losso)或者独立成分分析(ICA)。这样特征的维度会大大减小。再来拟合决策树模型效果会好。
推荐多用决策树的可视化,同时先限制决策树的深度(比如最多3层),这样可以先观察下生成的决策树里数据的初步拟合情况,然后再决定是否要增加深度。
在训练模型先,注意观察样本的类别情况(主要指分类树),如果类别分布非常不均匀,就要考虑用class_weight来限制模型过于偏向样本多的类别。
决策树的数组使用的是numpy的float32类型,如果训练数据不是这样的格式,算法会先做copy再运行。
如果输入的样本矩阵是稀疏的,推荐在拟合前调用csc_matrix稀疏化,在预测前调用csr_matrix稀疏化。
3.4 实例——鸢尾花多分类决策树
我们使用鸢尾花数据集对决策树的调参作进一步了解
3.4.1 导入数据
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn import tree
from sklearn.model_selection import train_test_split
from sklearn import metricsiris = load_iris()
iris_df = pd.DataFrame(np.concatenate((iris.data, iris.target.reshape(-1, 1)), axis = 1), columns = iris.feature_names + ['target'])
iris_df.head(7)
3.4.2 决策树可视化
clf = tree.DecisionTreeClassifier(random_state=20190711)
clf = clf.fit(iris.data, iris.target)# 可视化
plt.figure(dpi=200)
tree.plot_tree(clf, filled=True) # 报错AttributeError的话,更新一下scikit-learn;filled表示是否用颜色进行填充
plt.show()
# 更高级的可视化
import graphviz # 需要下载graphviz软件(官网下载即可)并添加到环境变量(永久)
import pydotplus
from IPython.display import Image
from subprocess import call#import os # 另一种添加环境变量的方法(一次性)
#os.environ["PATH"]+= os.pathsep + 'C:/Program Files (x86)/Graphviz2.38/bin/dot_data = tree.export_graphviz(clf, out_file='file/6/tree.dot', feature_names=iris.feature_names, class_names=iris.target_names, filled=True, rounded=True, special_characters=True) # 将树导出为 Graphviz 格式,生成 iris.dot 文件# 生成 iris.PDF,
#graph = pydotplus.graph_from_dot_data(dot_data) # 方法一
#graph.write_pdf('iris.pdf')#graph = graphviz.Source(dot_data) # 方法二
#graph.render("iris") # 生成PNG图像
call(['dot', '-Tpng','file/6/tree.dot', '-o', 'img/dt/tree.png', '-Gdpi=600'])
Image(filename ='img/dt/tree.png') # 在 Jupyter 中展示# 结果展示
#graph = pydotplus.graph_from_dot_data(dot_data) # 方法一(推荐)
#Image(graph.create_png())#graph = graphviz.Source(dot_data) # 方法二(图片过大)
#graph
3.4.3 交叉验证
拆分数据集并划分为训练集和验证集
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2)print("X_train_shape:", X_train.shape, " y_train_shape:", y_train.shape)
print("X_test_shape:", X_test.shape," y_test_shape:", y_test.shape)
X_train_shape: (120, 4) y_train_shape: (120,)
X_test_shape: (30, 4) y_test_shape: (30,)
clf = tree.DecisionTreeClassifier()
clf.fit(X_train, y_train)print("test score:", clf.score(X_test, y_test))
test score: 0.9666666666666667
dot_data = tree.export_graphviz(clf, out_file=None, feature_names=iris.feature_names, class_names=iris.target_names, filled=True, rounded=True, special_characters=True)graph = pydotplus.graph_from_dot_data(dot_data)
Image(graph.create_png())
新生成的树少了一些分支,这并不能说明问题,因为我们减少了用于拟合的数据。
3.4.4 调参
3.4.4.1 使用 max_depth 降低过拟合
def cv_score(d):clf = tree.DecisionTreeClassifier(max_depth=d)clf.fit(X_train, y_train)return(clf.score(X_train, y_train), clf.score(X_test, y_test))scores = [cv_score(d) for d in np.arange(1, 7)] # 前面的决策树使用最大深度:6,所以这里只需遍历1到6即可(由于划分随机性,深度可能不同)
tr_scores = [s[0] for s in scores]
te_scores = [s[1] for s in scores]scores
[(0.6833333333333333, 0.6),
(0.9583333333333334, 0.9333333333333333),
(0.9583333333333334, 0.9666666666666667),
(0.975, 0.9333333333333333),
(0.9916666666666667, 0.9666666666666667),
(1.0, 0.9666666666666667)]
plt.figure(figsize=(6,4), dpi=120)
plt.grid()
plt.xlabel('max depth of decison tree')
plt.ylabel('Scores')
plt.plot(np.arange(1, 7), te_scores, label='test_scores')
plt.plot(np.arange(1, 7), tr_scores, label='train_scores')
plt.legend()
plt.show()
可以看到当深度逐渐增加时,决策树在训练集的准确率逐渐增高,在测试集上当深度为3时达到最大值,但当深度达到5时再次取得了最大值,所以取最大深度6是最合适的
3.4.4.2 通过min_impurity_decrease来优化模型
这个参数用来指定信息墒或者基尼不纯度的阀值,当决策树分裂后,其信息增益低于这个阀值时则不再分裂
def minsplit_score(val):clf = tree.DecisionTreeClassifier(criterion='gini', min_impurity_decrease=val)clf.fit(X_train, y_train)return (val, clf.score(X_train, y_train), clf.score(X_test, y_test), )vals = np.linspace(0, 0.1, 100)
scores = [minsplit_score(v) for v in vals]
tr_scores = [s[1] for s in scores]
te_scores = [s[2] for s in scores]scores[:10]
[(0.0, 1.0, 0.9333333333333333),
(0.00101010101010101, 1.0, 0.9666666666666667),
(0.00202020202020202, 1.0, 0.9666666666666667),
(0.0030303030303030303, 1.0, 0.9666666666666667),
(0.00404040404040404, 1.0, 0.9666666666666667),
(0.00505050505050505, 1.0, 0.9333333333333333),
(0.006060606060606061, 0.9916666666666667, 0.9666666666666667),
(0.007070707070707071, 0.9916666666666667, 0.9666666666666667),
(0.00808080808080808, 0.9916666666666667, 0.9666666666666667),
(0.00909090909090909, 0.9916666666666667, 0.9666666666666667)]
plt.figure(figsize=(6,4), dpi=120)
plt.grid()
plt.xlabel("min_impurity_decrease")
plt.ylabel("Scores")
plt.plot(vals, te_scores, label='test_scores')
plt.plot(vals, tr_scores, label='train_scores')plt.legend()
plt.show()
可以看到当阈值逐渐增大时,决策树在训练集上的准确率会下降,在验证集上,当阈值在0.01~0.04时准确率最高。因为该参数值可以调整为0.02
clf = tree.DecisionTreeClassifier(criterion='gini', min_impurity_decrease=0.02)
clf.fit(X_train, y_train)print("train score:", clf.score(X_train, y_train))
print("test score:", clf.score(X_test, y_test))dot_data = tree.export_graphviz(clf, out_file=None, feature_names=iris.feature_names, class_names=iris.target_names, filled=True, rounded=True, special_characters=True)graph = pydotplus.graph_from_dot_data(dot_data)
Image(graph.create_png())
train score: 0.9583333333333334
test score: 0.9666666666666667
调整后的决策树深度只有3,并且有5个错分样本。
3.4.4.3 利用GridSearchCV求最优参数
如果想一起调整两个参数可以用不同的组合去试,但是显然这很麻烦,此外数据集划分的不确定性也会影响试验的结果,所以可以尝试利用GridSearchCV求最优参数。GridSearchCV会枚举列表里所有值来构建模型多次计算训练模型,并计算模型评分,最终得出指定参数值的平均评分及标准差。
3.4.4.3.1 单参数调整
from sklearn.model_selection import GridSearchCVthresholds = np.linspace(0, 0.1, 100)
param_grid = {'min_impurity_decrease':thresholds} # 对参数min_impurity_decrease进行遍历clf = GridSearchCV(tree.DecisionTreeClassifier(), param_grid, cv=5, return_train_score=True)
clf.fit(iris.data, iris.target)print("best_parms:{0}\nbest_score:{1}".format(clf.best_params_, clf.best_score_))
best_parms:{‘min_impurity_decrease’: 0.013131313131313131}
best_score:0.9733333333333334
最终得出最优参数及最优评分保存在clf.best_params_和clf.best_score_里。此外clf.cv_results_里保存了计算过程的所有中间结果,我们可以用这些结果来进行可视化
def plot_curve(train_sizes, cv_results, xlabel):train_scores_mean = cv_results['mean_train_score'] # GridSearchCV()的参数中要把return_train_score设置为Truetrain_scores_std = cv_results['std_train_score']test_scores_mean = cv_results['mean_test_score']test_scores_std = cv_results['std_test_score']plt.figure(figsize=(6, 4), dpi=120)plt.title('parameters turning')plt.grid()plt.xlabel(xlabel)plt.ylabel('score')plt.fill_between(train_sizes, train_scores_mean - train_scores_std,train_scores_mean + train_scores_std, alpha=0.1, color="r")plt.fill_between(train_sizes, test_scores_mean - test_scores_std,test_scores_mean + test_scores_std, alpha=0.1, color="g")plt.plot(train_sizes, train_scores_mean, '.--', color="r",label="Training score")plt.plot(train_sizes, test_scores_mean, '.-', color="g",label="Cross-validation score")plt.legend(loc="best")plt.show()plot_curve(thresholds, clf.cv_results_, xlabel='gini thresholds')
clf = tree.DecisionTreeClassifier(criterion='gini', min_impurity_decrease=0.013)
clf.fit(X_train, y_train)print("train score:", clf.score(X_train, y_train))
print("test score:", clf.score(X_test, y_test))dot_data = tree.export_graphviz(clf, out_file=None, feature_names=iris.feature_names, class_names=iris.target_names, filled=True, rounded=True, special_characters=True)graph = pydotplus.graph_from_dot_data(dot_data)
Image(graph.create_png())
train score: 0.9583333333333334
test score: 0.9666666666666667
3.4.4.3.2 多参数调整
entropy_thresholds = np.linspace(0, 1, 100) # 利用经验熵做选择标准
gini_thresholds = np.linspace(0, 0.2, 100)
#设置参数矩阵:
param_grid = [{'criterion': ['entropy'], 'min_impurity_decrease': entropy_thresholds},{'criterion': ['gini'], 'min_impurity_decrease': gini_thresholds},{'max_depth': np.arange(2,10)},{'min_samples_split': np.arange(2,30,2)}] # 对列表中的每个字典进行迭代,选出最优的参数对应的参数值for i in range(20):clf = GridSearchCV(tree.DecisionTreeClassifier(), param_grid, cv=5)clf.fit(iris.data, iris.target)print("best param:{0}\nbest score:{1}".format(clf.best_params_, clf.best_score_))
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.00202020202020202}
best score:0.9666666666666667
best param:{‘max_depth’: 3}
best score:0.9733333333333334
best param:{‘max_depth’: 3}
best score:0.9733333333333334
best param:{‘max_depth’: 3}
best score:0.9733333333333334
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.0}
best score:0.9666666666666667
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.0}
best score:0.9666666666666667
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.0}
best score:0.9666666666666667
best param:{‘max_depth’: 3}
best score:0.9733333333333334
best param:{‘max_depth’: 3}
best score:0.9733333333333334
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.006060606060606061}
best score:0.9666666666666667
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.0}
best score:0.9666666666666667
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.00404040404040404}
best score:0.9666666666666667
best param:{‘max_depth’: 3}
best score:0.9733333333333334
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.00404040404040404}
best score:0.9666666666666667
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.00202020202020202}
best score:0.9666666666666667
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.0}
best score:0.9666666666666667
best param:{‘max_depth’: 5}
best score:0.9666666666666667
best param:{‘criterion’: ‘gini’, ‘min_impurity_decrease’: 0.006060606060606061}
best score:0.9666666666666667
best param:{‘max_depth’: 3}
best score:0.9733333333333334
best param:{‘max_depth’: 3}
best score:0.9733333333333334
经过循环,我们得出最优参数:criterion=‘gini’;max_depth=3;min_impurity_decrease=0
clf = tree.DecisionTreeClassifier(criterion='gini', max_depth=3, min_impurity_decrease=0)
clf.fit(X_train, y_train)print("train score:", clf.score(X_train, y_train))
print("test score:", clf.score(X_test, y_test))dot_data = tree.export_graphviz(clf, out_file=None, feature_names=iris.feature_names, class_names=iris.target_names, filled=True, rounded=True, special_characters=True)graph = pydotplus.graph_from_dot_data(dot_data)
Image(graph.create_png())
train score: 0.9583333333333334
test score: 0.9666666666666667
4 sklearn回归决策树
分类决策树的函数为 sklearn.tree.DecisionTreeRegressor()
4.1 参数列表
参数名 | 参数类型 | 参数说明 |
---|---|---|
criterion | string, optional (default=”mse”) | 分裂的划分标准:“mse”表示均方误差(最小化L2损失);“friedman_mse”表示friedman最小平方误差(mse的近似);“mae”表示平均绝对误差(最小化L1损失) |
splitter | string, optional (default=”best”) | 见分类树 |
max_depth | int or None, optional (default=None) | 见分类树 |
min_samples_split | int, float, optional (default=2) | 见分类树 |
min_samples_leaf | int, float, optional (default=1) | 见分类树 |
min_weight_fraction_leaf | float, optional (default=0.) | 见分类树 |
max_features | int, float, string or None, optional (default=None) | 不同于分类树的是,这里的“auto”使用全部特征 |
random_state | int, RandomState instance or None, optional (default=None) | 见分类树 |
max_leaf_nodes | int or None, optional (default=None) | 见分类树 |
min_impurity_decrease | float, optional (default=0.) | 见分类树 |
presort | bool, optional (default=False) | 见分类树 |
4.2 属性列表
属性名 | 属性类型 | 属性说明 |
---|---|---|
feature_importances_ | array of shape = [n_features] | 特征重要性 |
max_features_ | int | 最大特征数 |
n_features_ | int | 特征数量 |
n_outputs_ | int | 输出数量(多输出决策树) |
tree_ | Tree object | 树结构 |
我们使用1个一维数据训练一棵决策树
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt# Create a random dataset
rng = np.random.RandomState(20190712)
X = np.sort(5 * rng.rand(80, 1), axis=0)
y = np.sin(X).ravel()
y[::5] += 3 * (0.5 - rng.rand(16)) # 设置偏移点# Fit regression model
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=4)
regr_3 = DecisionTreeRegressor(max_depth=6)
regr_1.fit(X, y)
regr_2.fit(X, y)
regr_3.fit(X, y)# Predict
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)
y_3 = regr_3.predict(X_test)# Plot the results
plt.figure(dpi = 120)
plt.scatter(X, y, s=20, edgecolor="black", c="black", label="data")
plt.plot(X_test, y_1, color="blue", label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="red", label="max_depth=4", linewidth=2)
plt.plot(X_test, y_3, color="orange", label="max_depth=6", linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()
可以看到当深度为6的时候决策树已经开始对异常数据进行拟合了,出现了过拟合现象,这也体现了决策树在处理异常数据方面的缺点
plt.figure(dpi=120)
tree.plot_tree(regr_3, filled=True)
plt.show()
5 参考文献
《统计学习方法》李航
《机器学习》周志华
sklearn文档
ihoge的博客
【机器学习笔记】——决策树(Decision Tree)相关推荐
- 机器学习笔记——决策树(Decision Tree)(1)
决策树 1.引入 1.1定义 决策树,顾名思义,就是帮我们做出决策的树.现实生活中我们往往会遇到各种各样的抉择,把我们的决策过程整理一下,就可以发现,该过程实际上就是一个树的模型.比如相亲的时候: ...
- 机器学习(五)决策树(decision tree)
决策树(decision tree)(一)--构造决策树方法 决策树算法起源于E.B.Hunt等人于1966年发表的论文"experiments in Induction",但真正 ...
- 机器学习:决策树(Decision Tree)介绍
简介 决策树是一种常见的机器学习算法,它的实现方式类似于我们平时利用多个不同权重选择做决策的过程.以下介绍一个现实生活中的例子. 当父母给自己的女儿介绍对象时,女儿往往会根据对方的年龄.富贵.高矮.美 ...
- 机器学习:决策树(Decision Tree)--ID3算法
决策树的主要算法 构建决策树的关键:按照什么样的次序来选择变量(属性/特征)作为分类依据. 根据不同的目标函数,建立决策树主要有以下三种算法 ID3(J.Ross Quinlan-1975) 核心:信 ...
- [机器学习笔记] (四)决策树 Decision Tree
(四)决策树 Decision Tree 基本概念 决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性 ...
- 机器学习算法实践:决策树 (Decision Tree)(转载)
前言 最近打算系统学习下机器学习的基础算法,避免眼高手低,决定把常用的机器学习基础算法都实现一遍以便加深印象.本文为这系列博客的第一篇,关于决策树(Decision Tree)的算法实现,文中我将对决 ...
- 【机器学习实验二】决策树(Decision Tree)及其在图像识别任务上的应用
经典有监督学习算法:决策树(Decision Tree) --本篇博客的决策树算法以及实验仅针对分类问题 文章目录 经典有监督学习算法:决策树(Decision Tree) 1.算法简介 2.算法思想 ...
- 决策树Decision Tree 和随机森林RandomForest基本概念(一)
文章目录 一.决策树介绍 1.1 什么是决策树 1.2 决策树种类 1.3 决策树学习过程 1.4 Entropy(熵) 1.5 information gain(信息增益) 1.6 信息论 1.8 ...
- Machine Learning | (7) Scikit-learn的分类器算法-决策树(Decision Tree)
Machine Learning | 机器学习简介 Machine Learning | (1) Scikit-learn与特征工程 Machine Learning | (2) sklearn数据集 ...
- Scikit-Learn 机器学习笔记 -- 决策树
Scikit-Learn 机器学习笔记 – 决策树 参考文档: handson-ml import numpy as np# 加载鸢尾花数据集 def load_dataset():from skle ...
最新文章
- getRemoteAddr()和getRemoteHost() 区别
- c# socket接收字符串_socket通信很难?这一文让你轻松搞定!
- 你的 Docker 应用是安全的吗?
- 数字图像处理与python实现 pdf_正版 数字图像处理与Python实现 高等院校计算机科学 人工智能 信号与信息处理 通信工程等专业的...
- IOS(常用移动终端设备) push实现通知中心
- linux文件操作命令介绍(一)
- php实现从尾到头打印列表
- Kettle行列转换
- 实验3: DHCP 基本配置
- java中蓝色是多少_JAVA几个常见错误简析
- 10、【易混淆概念集】-第六章1 三点估算 类比估算和参数估算的区别 储备分析 历时估算 项目进度网络图
- 一些临时邮箱服务网站
- 在职读研难,社科院与杜兰大学金融管理硕士项目让读研多了一种选择
- Linux学习笔记(四)Linux基础操作
- 安卓(Android)手机Flash Player官方下载地址
- 通达信软件接口是什么?能看得到五档报价吗?
- 十七、网上商城项目(6)
- 韩创变色镜片和普通镜片哪个更好用
- CentOS 7 多硬盘合并 mergerfs 磁盘合并 + Duf 磁盘容量查看
- vscode中前端vue项目详解_vs code 第一次创建前端项目 vuejs 从零开始