决策树
应用场景
- 客户细分:企业可以利用决策树对客户进行细分,识别不同客户群体的特征,从而提供更加个性化的服务和产品。
- 风险评估:在金融行业,决策树常用于评估贷款申请者的信用风险,帮助银行和金融机构决定是否批准贷款以及贷款的条件。
- 商品分类
- 产品推荐:决策树分析用户行为,为用户推荐可能感兴趣的商品,增强用户体验并提高销售额。
- 欺诈检测:决策树可以用于识别异常模式和欺诈行为,如信用卡欺诈或保险欺诈。
1.认识决策树
-
决策树(Decision Tree)是一种有监督学习,它能够从一系列有特征和标签的数据中总结出决策(基于分类或回归)规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。
-
决策树算法容易理解,适用各种数据,在解决各种问题时都有良好表现,尤其是以树模型为核心的各种集成算法,在各个行业领域都有广泛的应用
-
决策树算法的本质是一种树结构,我们只需要问一系列的问题就可以对数据进行分类。
-
最初的问题为根节点,得到结论前的每一个问题是中间节点,得到的每一个结论叫做叶子结点
-
节点
- 根节点:没有进边,有出边,包含最初的针对最初的提问
- 中间节点:既有进边又有出边,进边只有一条,出边可以有多条,都是针对特征的提问
- 叶子结点:有进边,无出边,每个叶子结点都是一个类别标签
- 子节点和父节点:在两个相连的节点中,更接近根节点的是父节点,另一个是子节点
-
注意
- 树的根节点和中间节点对应的是某一类型特征,这些节点(特征)自上而下的重要性是由大到小进行排列的
2.决策树算法主要解决的问题
- 决策树算法的核心是要解决两个问题
- 如何找出最佳节点或最佳分枝?
- 如何让决策树停止生长,防止过拟合?
- 决策树是基于训练集数据构建出来的,如果树长的越大分支枝越细,则对训练数据的描述越清楚,但是不一定会很好的作用到测试数据中
3.构建决策树
- 任意一个数据集上的所有特征都可以拿来分枝,特征上的任意节点又可以自由组合,所以一个数据集上可以发展出多棵决策树,其数量可达指数级。在这些树中,一定有一颗树比其他树分类效果好,这棵树叫"全局最优树"。
- 全局最优:经过最优组合形成的决策树,整体来说分类效果为最好的模型
- 局部最优:每一次分枝的时候都向着更好的分类效果分枝,但无法确认如此生成的树是否是全局最优的
- 机器学习研究者们开发了一些有效的算法,能够在合理的时间内构造出具有一定准确率的次最优树
- 这些算法都执行"贪心策略",即通过局部的最优来达到我们相信是最接近全局最优(次最优决策树)的结果
3.2贪心算法
- 通过实现局部最优来达到接近全局最优结果的算法,所有的树模型都是这样的算法
4.不纯度
-
在一组数据中,如果有某一类标签占有较大的比例,则该节点越"纯",分枝分的越好,叶子就越纯,不纯度越低
- 如果90%样本数据都是类别0(节点比较纯),新进入该节点的测试样本的类别很可能是0.
-
如果没有哪一类标签的比例很大,各类标签都相对平均,则该节点"不纯",分枝不好,不纯度高
- 如果51%的样本是0,49%的样本是1(极端情况),该节点还是会被认为0节点,但是样本点几乎有一半可能性应该是1类别
-
分类型决策树在节点上的决策规则是少数服从多数,在一个节点上,如果某一类标签所占的比例较大,那所有进入这个节点的样本都会被认为是这个类别
-
从数学上来说,类分布为(0,100%),的节点具有零不纯性,而均匀分布(50%,50%)节点具有最高的不纯性。如果节点本身不纯,那测试样本很可能判断错误,相对的节点越纯,样本判断错误的可能性越小
5.ID3算法构建决策树
- 最典型的决策树算法是Hunt算法,该算法是由Hunt等人提出的最早的决策树算法,Hunt算法是许多决策树算法的基础,包括ID3,C4.5和CART等
- ID3算法原形见于J.R Quinlan的博士论文,是基础理论较为完善,使用较为广泛的决策树模型算法,在此基础上J.R Quinlan进行优化后,陆续推出了C4.5决策树算法,后者现已称为当前最流行的决策树算法
- 为了要将数据集转化为一棵树,决策树需要找出最佳节点和最佳的分枝方法,衡量这个"最佳的"的指标叫做"不纯度"。不纯度基于叶子节点来计算,所以树中的每个节点都会有一个不纯度,并且子节点的不纯度一定低于父节点,即,在同一棵决策树上,叶子结点的不纯度一定是最低的
5.1信息论基础
-
问题:现在有32支球队,然后猜出谁是冠军!
- 32只球队猜对的代价为log32=5次,64只球队猜对的代价为log64=6次,以信息论的角度来讲的话,代价为5次或者代价为6次被称为代价为5比特或者代价为6比特。
-
比特:就是信息论中信息度量的单位也叫做信息量,这个概念是由信息论的创始人【香农】提出的
-
信息论中提出信息量的值会随着更多有用的信息的出现而降低
- 信息量的值在信息论中被称为信息熵
- 比特或信息量就是信息熵的单位
- 信息熵:是一种信息的度量方式,表示信息的混乱程度,也就是说:信息越有序,信息熵越低(不纯度或者信息量越低)
- 结论:信息熵和消除不确定性是相关联的
- 信息熵越大则表示信息的不确定性越大,猜对的代价大
- 信息熵越小则表示信息的不确定性越小,猜对的代价小
5.2信息增益
-
我们的分类结果是要从树的根节点开始自上而下的进行分步判断从而得到正确的划分结论。越重要的节点作为树中越靠上的节点可以减少基于该树进行分类的更多的不确定性
-
如何衡量决策树中节点(特征)的重要性?如何理解特征的重要性
- 重要性:如果一个节点减少分类的不确定性越明显,则该点就越重要
- 使用信息增益衡量特征的重要性
-
信息增益:
- 在根据某个特征划分数据集之前之后信息熵发生的变化或差异叫信息增益,增益最高的特征就是最好的选择
- 信息增益作为决策树的划分依据,决定决策树怎么画,每个特征作为节点存放的位置
- 计算出每个特征的信息增益,特征的信息增益越大,则表示该特征越重要,应该放在决策树靠上的位置
- 公式
- 信息增益=划分前熵-划分后熵
5.3构建决策树
-
在构建决策树时,要解决三个重要的问题
- 选择那个属性作为根节点
- 选择哪个属性作为子节点
- 什么时候停止并且得到目标状态,即子节点
-
案例【气象数据】
- 在没有使用特征划分类别的情况下,有9个yes和5个no,当前的熵为:
- 以 outlook 特征作为决策树的根节点划分数据集,对该特征每项指标分别统计:在不同的取值下 play 和 no play 的次数:
- 此时各分支的熵计算如下:
- 因此如果用特征outlook来划分数据集的话,总的熵为【每一个outlook的组成的信息熵乘以outlook组成占总样本的比例】
最终得到特征属性outlook带来的信息增益为:
g(outlook)=0.940−0.694=0.246
temperature,humidity,windy的信息增益分别为:
IG(temperature)=0.029
IG(humidity)=0.152
IG(windy)=0.048
可以得出使用outlook特征所带来的信息增益最大。因此第一次切分过程将采用outlook字段进行切分数据集。
5.4 ID3的局限性
- 不能直接处理连续型数据集,若要使用ID3处理连续型变量,首先需要对连续变量进行离散化
- 对缺失值较为敏感,使用ID3之前需要提前对缺失值进行处理
- 存在缺失值则信息熵的公式无法计算结果
- 没有剪枝的设置,容易导致过拟合
6. C4.5算法
-
C4.5信息增益比
-
分支度
- 在C4.5中,引入了分支度的概念。分支度的计算仍然是基于熵的算法,只是将信息熵计算公式中的p(xi)【某类别样本数量占总样本数量】改为p(vi)【即某子节点的总样本数占父节点总样本数】,p(vi)就是“权重”,分支度指标,在切分的时候,自动避免那些分类水平太多,信息熵减少过快的特征影响模型,减少过拟合情况
-
参数
i
表示父节点的第i
个子节点vi
表示第i
个子节点样例数p(vi)
表示第i
个子节点拥有样例数占父节点总样例数的比例
-
IV可作为惩罚项带入子节点的信息熵计算中,所以IV值会随着叶子结点上样本量的变小而逐渐变大,就是说一个特征中如果标签分类太多,每个叶子上的IV值就会非常大,树的分值就会越细
I n f o r m a t i o n V a l u e = − ∑ i = 1 k p ( v i ) log 2 p ( v i ) Information \ Value=-\sum_{i=1}^{k}p(v_i)\log_2p(v_i) Information Value=−i=1∑kp(vi)log2p(vi) -
在C4.5中,使用之前的信息增益除以分支度作为分值的参考指标,该指标称作Gain Ratio(信息增益比)
G a i n R a t i o = I n f o r m a t i o n G a i n I n f o r m a t i o n V a l u e Gain \ Ratio=\frac{Information\ Gain}{Information \ Value} Gain Ratio=Information ValueInformation Gain -
增益比例是我们决定对哪一列进行分支的标准,我们分支的是数字最大的那一列,本质是信息增益最大,分支度有较小的列(也就是纯度提升很快,但又不是因为把类别分特别细来提升的那些特征),IV越大,即某一列的分类水平越多,Gain ratio实现的惩罚比例越大,我们希望GR越大越好
-
7.CART(基尼系数)
-
CART全称是分类与回归树,CART既可以用于分类问题,也可以用于回归问题
-
CART与ID3,C4.5不同之处在于CART生成的树必须是二叉树,无论是回归还是分类问题,无论特征是离散的还是连续的,无论属性有多个还是两个,内部节点只能根据属性值进行二分
G i n i = 1 − ∑ i = 0 c − 1 [ p ( i ∣ t ) ] 2 Gini=1-\sum_{i=0}^{c-1}[p(i|t)]^2 Gini=1−i=0∑c−1[p(i∣t)]2
8.如何选取算法
- 在实际使用中,信息熵和基尼系数的效果基本一致。信息熵的计算比基尼系数慢一点,因为基尼系数的计算不涉及对数,此外,因为信息熵对不纯度更加敏感,所以信息熵作为指标时,决策树的生长更加"精细",因此对于高维数据或者噪音很多的数据,信息熵容易过拟合,基尼系数在这种情况下效果比较好,当模型拟合程度不足时,即当模型在训练集和测试集上表现都不好时,使用信息熵,但是不是绝对的
9.API
class sklearn.tree.DecisionTreeClassifier(
criterion=’gini’,
splitter=’best’,
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features=None,
random_state=None,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
class_weight=None,
presort=False
)[source]
-
参数
参数 含义 random_state 用来设置分枝中的随机模式的参数,默认为None,在高维度时随机性会表现更明显,低维度的数据(比如鸢尾花数据集),随机性几乎不会显现,输入任意整数,会一直长出同一棵树,让模型稳定下来 splitter 用来控制决策树中的随机选项,有两种值 best 决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝(重要性可以通过属性 feature_importances_
查看)random 决策树在分支时会更加随机,树会因为含有更多的不必要信息而更深更大,因这些不必要信息而降低队训练集的拟合,是防止过拟合的一种方式 -
当预测模型可能会出现过拟合,通过这两个参数降低树建成后过拟合的可能性
-
剪枝参数
参数 含义 max_depth 限制树的最大深度,超过设定深度的树全部剪掉(这是最广泛的剪枝参数,在高维度低样本量时非常有效,决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合,在集成算法也非常实用) min_samples_leaf 限定一个节点在分枝后的每个子节点必须包含至少 min_samples_leaf
个训练样本,否则分枝不会发生或分枝会朝着满足每个子节点都包含min_samples_leaf
个样本的方向去发生,一般搭配max_depth
使用,这个参数设置太小会导致过拟合,设置太大会导致模型学习数据min_samples_split 限定一个节点必须包含至 min_samples_split
个训练样本,这个节点才允许被分枝,否则,分枝不会发生
10.网格搜索调整参数
名称 | 含义 |
---|---|
Grid Search | 一种调参手段:穷举搜索;在所有候选的参数选择中,通过循环遍历,尝试每一种可能性,表现最好的参数就是最终的结果,其原理就像是在数组里找最大值 |
-
为什么叫网格搜索?
- 以有两个参数的模型为例,参数a有3种可能,参数b有4种可能,把所有可能性列出来,可以表示成一个3*4的表格,其中每个cell就是一个网格,循环过程就像是在每个网格里遍历、搜索,所以叫
grid search
- 以有两个参数的模型为例,参数a有3种可能,参数b有4种可能,把所有可能性列出来,可以表示成一个3*4的表格,其中每个cell就是一个网格,循环过程就像是在每个网格里遍历、搜索,所以叫
11.示例
-
画一棵树
import graphviz from sklearn import tree from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split dt=load_wine() feature=dt.data target=dt.target x_train,x_test,y_train,y_test=train_test_split(feature,target,test_size=0.2,random_state=2020) clf=DecisionTreeClassifier(criterion='entropy') clf.fit(x_train,y_train) clf.score(x_test,y_test) feature_name=['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸'] dot_data=tree.export_graphviz(clf, out_file=None,#图片保存路径 feature_names=feature_name, class_names=["琴酒","雪莉","贝尔摩德"], filled=True #使用颜色表示分类结果 ) graph=graphviz.Source(dot_data) graph #feature_importances_为重要参数 feature_name=['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜 色强度','色调','od280/od315稀释葡萄酒','脯氨酸'] [*zip(feature_name,clf.feature_importances_)] # [('酒精', 0.0), # ('苹果酸', 0.01479390227172555), # ('灰', 0.0), # ('灰的碱性', 0.031155237629119946), # ('镁', 0.0), # ('总酚', 0.0), # ('类黄酮', 0.48742660098390633), # ('非黄烷类酚类', 0.008964941814890645), # ('花青素', 0.0), # ('颜 色强度', 0.2925389040029275), # ('色调', 0.0), # ('od280/od315稀释葡萄酒', 0.0), # ('脯氨酸', 0.16512041329743002)]
-
参数
splitter
示例from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split from sklearn import tree dt=load_wine() feature=dt.data target=dt.target x_train,x_test,y_train,y_test=train_test_split(feature,target,test_size=0.2,random_state=2020) clf=tree.DecisionTreeClassifier(criterion='entropy',random_state=20,splitter='best') clf=clf.fit(x_train,y_train) score=clf.score(x_test,y_test) score #0.9722222222222222
-
剪枝参数示例
from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split from sklearn import tree import graphviz dt=load_wine() feature=dt.data target=dt.target x_train,x_test,y_train,y_test=train_test_split(feature,target,test_size=0.2,random_state=2020) clf=tree.DecisionTreeClassifier(criterion='entropy',random_state=30,splitter='random',max_depth=4,min_samples_leaf=10,min_samples_split=10) clf=clf.fit(x_train,y_train) dot_data=tree.export_graphviz(clf,feature_names=feature_name,class_names=["琴酒","雪莉","贝尔摩德"],filled=True,out_file=None) graph=graphviz.Source(dot_data) graph
-
网格搜索调参示例
import numpy as np from sklearn.model_selection import GridSearchCV parameters = {'splitter':('best','random') ,'criterion':("gini","entropy") ,"max_depth":[*range(1,10)] ,'min_samples_leaf':[*range(1,50,5)] } clf = DecisionTreeClassifier(random_state=25) GS = GridSearchCV(clf, parameters, cv=10) GS.fit(Xtrain,Ytrain) GS.best_params_ #{'criterion': 'gini', # 'max_depth': 4, # 'min_samples_leaf': 1, # 'splitter': 'random'}