决策树模型就是通过特征点构造一个决策树(根据特征回答是和否的问题),把最重要的特征也就是对分类最明显的特征放在上面(选择最优划分属性),构建一个树,预测类别时我们走完一遍树也就可以预测出类别了。
通过决策树可以得到特征的重要性得分
构造决策树是一个递归过程,在决策树基本算法中有三种情形会导致递归返回:
1. 当前结点的样本全属于同一类别(都是好瓜或都是坏瓜),无需划分
2. 当前属性集为空或所有样本在所有属性上取值相同,无法划分
这种情况下我们把当前结点标记为叶结点,并将其类别设定为该结点所含样本最多的类别(若最多的类不唯一,则任选一类)
3. 当前结点包含的样本集合为空,不能划分
同样把当前结点标记为叶节点,但是类别设定为父结点所含样本最多的类别
决策树学习的关键是如何选择最优划分属性,随着划分过程不断进行,我们希望决策树的分支结点所包含的样本尽可能属于同一类别,也就是结点的纯度越来越高。
通俗的来说:
常用的有以下几种方法:信息增益、增益率和基尼指数。
至于是信息增益还是基尼指数,主要区别就是纯度的度量方法不同。信息增益纯度的度量方法是信息熵,基尼指数纯度的度量方法是基尼值。
信息熵就是度量样本集合纯度最常用的指标,公式如下:
Ent(D)=−∑|y|k=1pklog2pk E n t ( D ) = − ∑ k = 1 | y | p k l o g 2 p k
Ent(D)的值越小,则D的纯度越高
信息增益就是基于上述的思想,用样本集合D的信息熵减去用某一属性划分的集合的信息熵之和,公式如下:
Gain(D,a)=Ent(D)−∑Vv=1|Dv||D|Ent(Dv) G a i n ( D , a ) = E n t ( D ) − ∑ v = 1 V | D v | | D | E n t ( D v )
信息增益越大,则意味着使用属性a来进行划分所获得的纯度提升越大。所以,我们计算出所有属性的信息增益,然后选择信息增益最大的。
由于信息增益准则对可取值数目较多的属性有所偏好,为减少这种偏好带来的不利影响,就有了增益率:
Gain_ratio(D,a)=Gain(D,a)IV(a) G a i n _ r a t i o ( D , a ) = G a i n ( D , a ) I V ( a )
IV(a)=−∑Vv=1|Dv||D|log2|Dv||D| I V ( a ) = − ∑ v = 1 V | D v | | D | l o g 2 | D v | | D |
其中,IV(a)为a的固有值,属性a的可能取值数目越多(即V越大),则IV(a)的值通常会越大。这样的话,增益率又对可取值数目较少的属性有所偏好。
所以在选择划分属性的时候,可以先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择增益率最高的。
基尼指数中数据集D的纯度用的是基尼值来度量:
Gini(D)=1−∑|y|k=1p2k G i n i ( D ) = 1 − ∑ k = 1 | y | p k 2
Gini反映了从数据集D中随机抽取两个样本,其类别标记不一致的概率。即Gini(D)越小,数据集D的纯度越高。
则属性a的基尼指数为:
Gini_index(D,a)=∑Vv=1|Dv||D|Gini(Dv) G i n i _ i n d e x ( D , a ) = ∑ v = 1 V | D v | | D | G i n i ( D v )
在选择划分属性的时候,选择基尼指数最小的属性作为最优划分属性
构建树的过程主要就是使用上述的划分方法:(以信息增益为例)
- 从根节点开始,计算所有特征值的信息增益,选择计算结果最大的特征作为根节点
- 根据算出的特征建立子节点,执行第1步,直到所有特征的信息增益(信息增益比)很小或没有特征可以选择为止
直接按照上述构建树的过程很容易产生过拟合,剪枝就是决策树学习算法中对付过拟合的主要手段,也就是主动去掉一些分支来降低过拟合的风险。
根据剪枝的时间,剪枝策略分为预剪枝和后剪枝。预剪枝是构造树的同时进行剪枝,后剪枝是决策树构建完后再进行剪枝。
剪枝策略 | 预剪枝 | 后剪枝 |
---|---|---|
思想 | 在生成决策树的同时,对每个结点在划分前先进行估计,若当前划分不能带来泛化能力提升,则停止划分当前结点 | 先生成完整决策树,再自底向上对非叶节点进行考查,若该结点对应子树替换为叶节点能提升泛化能力,则替换 |
优点 | ①降低过拟合风险 ②显著减少训练时间开销和测试时间开销 | 欠拟合风险小,泛化性能往往优于预剪枝决策树 |
缺点 | 有些分支当前虽不能提升泛化能力,甚至导致泛化能力下降,但在其基础上可能会导致性能显著提高,预剪枝基于贪心本质禁止这些分支展开,带来欠拟合风险 | 训练时间开销大得多 |
上述评估决策树的泛化能力有多种,如留出法、交叉验证等。主要思想就是留出一部分数据集作为验证集进行性能评估。
当属性为连续值时,我们首先要把其进行划分,然后再用划分选择的方法选取最优的划分点进行样本集合的划分。
我们一般是基于离散属性来生成决策树,遇到连续属性时要用到连续属性离散化技术,最简单的策略是二分化。具体做法如下:
对连续属性a,把区间 [ai+ai+1) [ a i + a i + 1 ) 的中位点作为候选划分点:
Ta={ai+ai+12|1≤i≤n−1} T a = { a i + a i + 1 2 | 1 ≤ i ≤ n − 1 }
这样我们就可以像离散属性值一样来考察这些划分点
将连续值变成离散点后,我们可计算将样本集D基于划分点t二分后的信息增益的最大值:
Gain(D,a)=maxt∈TaGain(D,a,t)=maxt∈TaEnt(D)−∑λ∈{−,+}|Dλt||D|Ent(Dλt) G a i n ( D , a ) = max t ∈ T a G a i n ( D , a , t ) = max t ∈ T a E n t ( D ) − ∑ λ ∈ { − , + } | D t λ | | D | E n t ( D t λ )
最后要注意的是,若当前结点划分属性为连续属性,该属性还可以作为其后代结点的划分属性。
现实情况下得到的数据都是不完整的,有很多样本属性都有缺失值,这样我们要解决的两个问题为:
对与问题1:在属性缺失的情况下进行划分属性选择
我们只能在D中挑选出那些没有缺失值的样本 D1 D 1 ,然后根据 D1 D 1 判断属性a的优劣
然后将信息增益的计算推广为:
Gain(D,a)=ρ×Gain(D1,a)=ρ×(Ent(D1)−∑Vv=1rvEnt(Dv1)) G a i n ( D , a ) = ρ × G a i n ( D 1 , a ) = ρ × ( E n t ( D 1 ) − ∑ v = 1 V r v E n t ( D 1 v ) )
其实就是把原来的信息增益变成无缺失样本的比例乘无缺失样本的信息增益
其中, ρ=∑x∈D1wx∑x∈Dwx ρ = ∑ x ∈ D 1 w x ∑ x ∈ D w x 表示无缺失值样本所占的比例
Ent(D1)=−∑|y|k=1pklog2pk E n t ( D 1 ) = − ∑ k = 1 | y | p k l o g 2 p k
pk=∑x∈D1kwx∑x∈D1wx p k = ∑ x ∈ D 1 k w x ∑ x ∈ D 1 w x 表示无缺失样本中第k类所占比例
rv=∑x∈D1vwx∑x∈D1wx r v = ∑ x ∈ D 1 v w x ∑ x ∈ D 1 w x 表示无缺失值样本中在属性a上取值 av a v 的样本所占的比例
对于问题2:给定划分属性,若样本在该属性上的值缺失,如何对样本进行划分
①若样本x在划分属性a的取值已知,则划入相对应子结点,权重保持为 wx w x
②若样本x在划分属性a的取值未知,则同时划入所有子结点,且样本权重在于属性值 av a v 对应子结点调整为 rvwx r v w x ,即让同一个样本以不同概率划入到不同子结点
若把每个属性视为坐标空间中的一个坐标轴,则d个属性描述的样本就对应了d维空间中的一个数据点,样本分类就是在这个坐标空间中寻找不同类样本之间的分类边界。
决策树形成的分类边界有一个明显特点:轴平行,即它的分类边界由若干个与坐标轴平行的分段组成。这样的分类边界使得学习结果又较好的可解释性
多变量决策树是实现用斜的划分边界的决策树,在此类决策树种,非叶结点不再是仅对于某个属性,而是对属性的线性组合进行测试,即每个非叶结点都是形如
∑di=1wiai=t ∑ i = 1 d w i a i = t 的线性分类器。
因此与传统的单变量决策树相比,多变量决策树的学习过程中,不是为每个非叶结点寻找一个最优划分属性,而是试图建立一个合适的线性分类器
•max_depth:树的最大深度(分割点的个数),最常用的用于减少模型复杂度防止过拟合的参数
•min_samples_leaf:每个叶子拥有的最少的样本个数
•max_leaf_nodes:树中叶子的最大个数
实际应用中,通常只需要调整max_depth就已足够防止决策树模型的过拟合
dt_model = DecisionTreeClassifier(max_depth=max_depth_val)
dt_model.fit(X_train, y_train)
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=0)
max_depth_values = [2, 3, 4]
for max_depth_val in max_depth_values:
dt_model = DecisionTreeClassifier(max_depth=max_depth_val)
dt_model.fit(X_train, y_train)
print('max_depth=', max_depth_val)
print('训练集上的准确率: {:.3f}'.format(dt_model.score(X_train, y_train)))
print('测试集的准确率: {:.3f}'.format(dt_model.score(X_test, y_test)))
print()
graphviz程序(已提供在代码目录下),并将安装目录下的bin目录添加到环境变量中,重启jupyter或系统生效。如:C:\Program Files (x86)\Graphviz2.38\bin 添加到系统PATH环境变量中。
graphviz模块, pip install graphviz
from ml_visualization import plot_decision_tree
dt_model = DecisionTreeClassifier(max_depth=4)
dt_model.fit(X_train, y_train)
plot_decision_tree(dt_model, iris.feature_names, iris.target_names)
print(iris.feature_names)
print(dt_model.feature_importances_)
from ml_visualization import plot_feature_importances
plot_feature_importances(dt_model, iris.feature_names)