决策树模型及案例(Python)

Posted QYiRen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了决策树模型及案例(Python)相关的知识,希望对你有一定的参考价值。

目录

1 决策树模型简介

2 Gini系数(CART决策树)

3 信息熵、信息增益

4 决策树模型代码实现

4.1 分类决策树模型(DecisionTreeClassifier)

4.2 回归决策树模型(DecisionTreeRegressor)

5 案例:员工离职预测模型

5.1 模型搭建

5.1.1 数据读取与预处理

5.1.2 提取特征变量和目标变量

5.1.3 划分训练集与测试集

5.1.4 模型搭建及训练

5.1.5 代码汇总

5.2 模型预测及评估

5.2.1 直接预测是否离职

5.2.2 预测不离职与离职的概率

5.2.3 模型预测效果评估(ROC曲线)

5.2.4 特征重要性评估

6 参数调优

6.1 K折交叉验证

6.2 GridSearch网格搜索

6.2.1 单参数调优

6.2.2 多参数调优

补充知识点:决策树的前剪枝和后剪枝

补充知识点:分类决策树模型DecisionTreeClassifier()的常用超参数

补充知识点:树模型在金融大数据风控领域的应用 


1 决策树模型简介

基本原理是通过对一系列问题进行if/else的推导,最终实现相关决策。

决策树模型的一个实例:

决策树的概念并不复杂,主要是通过连续的逻辑判断得出最后的结论,其关键在于如何建立这样一棵“树”。

2 Gini系数(CART决策树)

决策树模型的建树依据主要用到的是基尼系数的概念。

采用基尼系数进行运算的决策树也称为CART决策树。

基尼系数(gini)用于计算一个系统中的失序现象,即系统的混乱程度(纯度)。基尼系数越高,系统的混乱程度就越高(不纯),建立决策树模型的目的就是降低系统的混乱程度(体高纯度),从而得到合适的数据分类效果。

基尼系数的计算公式如下。

其中pi为类别i在样本T中出现的频率,即类别为i的样本占总样本个数的比率。

例如,一个全部都是离职员工的样本中只有一个类别——离职员工,其出现的频率是100%,所以该系统的基尼系数为1-1^2=0,表示该系统没有混乱,或者说该系统的“纯度”很高。而如果样本中一半是离职员工,另一半是未离职员工,那么类别个数为2,每个类别出现的频率都为50%,所以其基尼系数为1-(0.5^2+0.5^2)=0.5,即其混乱程度很高。

当引入某个用于分类的变量(如“满意度<5”)时,分类后的基尼系数公式如下。

其中S1、S2为划分后的两类各自的样本量,gini(T1)、gini(T2)为两类各自的基尼系数。

例如,一个初始样本中有1000个员工,其中已知有400人离职,600人不离职。划分前该系统的基尼系数为1-(0.42+0.62)=0.48,下面采用两种方式决定根节点:一是根据“满意度<5”进行分类;二是根据“收入<10000元”进行分类。

划分方式1:以“满意度<5”为根节点进行划分,如下图所示,计算过程如下。

T1的基尼系数:gini(T1)=1-(1^2+0^2)=0

T2的基尼系数:gini(T2)=1-(0.25^2+0.75^2)=0.375

划分方式2:以“收入<10000元”为根节点进行划分,如下图所示,计算过程如下。

T1的基尼系数:gini(T1)=1-(0.25^2+0.75^2)=0.375

T2的基尼系数:gini(T2)=1-(0.5^2+0.5^2)=0.5

可以看到,划分前的基尼系数为0.48,以“满意度<5”为根节点进行划分后的基尼系数为0.3,而以“收入<10000元”为根节点进行划分后的基尼系数为0.45。

基尼系数越低表示系统的混乱程度越低(纯度越高),区分度越高,越适合用于分类预测,因此这里选择“满意度<5”作为根节点。

3 信息熵、信息增益

除了基尼系数,还有另一种衡量系统混乱程度的经典手段——信息熵。

在搭建决策树模型时,信息熵的作用和基尼系数是基本一致的,都可以帮助合理地划分节点。

信息熵H(X)的计算公式如下。

其中X表示随机变量,随机变量的取值为X1,X2,X3…,在n分类问题中便有n个取值,例如,在员工离职预测模型中,X的取值就是“离职”与“不离职”两种;pi表示随机变量X取值为Xi的发生频率,且有Σpi=1。

举例来说,一个全部都是离职员工的样本中只有一个类别——离职员工,其出现的频率是100%,所以该系统的信息熵为-1×log1=0,表示该系统没有混乱。而如果样本中一半是离职员工,另一半是未离职员工,那么类别个数为2,每个类别出现的频率都为50%,所以该系统的信息熵为-(0.5×log0.5+0.5×log0.5)=1,表示该系统混乱程度很高。

当引入某个用于进行分类的变量A(如“满意度<5”),则根据变量A划分后的信息熵又称为条件熵,其计算公式如下。

其中S1、S2为划分后的两类各自的样本量,H(X1)、H(X2)为两类各自的信息熵。

为了衡量不同划分方式降低信息熵的效果,还需要计算分类后信息熵的减少值(原系统的信息熵与分类后系统的信息熵之差),该减少值称为熵增益或信息增益,其值越大,说明分类后的系统混乱程度越低,即分类越准确。

信息增益的计算公式如下。

继续用前面讲解基尼系数时的例子来讲解信息熵的应用。初始样本有1000个员工,其中已知有400人离职,600人不离职。划分前该系统的信息熵为-(0.4×log0.4+0.6×log0.6)=0.97,混乱程度较高。下面采用两种方式决定根节点:一是根据“满意度<5”进行分类;二是根据“收入<10000元”进行分类。

划分方式1:以“满意度<5”为根节点进行划分,如下图所示,计算过程如下。

初始信息熵:H(X)=-(0.4×log0.4+0.6×log0.6)=0.97

X1的信息熵:H(X1)=-(1×log1+0×log0)=0

X2的信息熵:H(X2)=-(0.25×log0.25+0.75×log0.75)=0.81

信息增益:Gain(A)=H(X)-HA(X)=0.97-0.65=0.32

划分方式2:以“收入<10000元”为根节点进行划分,如下图所示,计算过程如下。

初始信息熵:H(X)=-(0.4×log0.4+0.6×log0.6)=0.97

X1的信息熵:H(X1)=-(0.25×log0.25+0.75×log0.75)=0.81

X2的信息熵:H(X2)=-(0.5×log0.5+0.5×log0.5)=1

信息增益:Gain(B)=H(X)-HB(X)=0.97-0.924=0.046

根据方式1划分后的信息增益为0.32,大于根据方式2划分后的信息增益0.046,因此选择根据方式1进行决策树的划分,这样能更好地降低系统的混乱程度。这个结论和之前用基尼系数计算得到的结论是一样的。

基尼系数涉及平方运算,而信息熵涉及相对复杂的对数函数运算,因此,目前决策树模型默认使用基尼系数作为建树依据,运算速度会较快。

4 决策树模型代码实现

4.1 分类决策树模型(DecisionTreeClassifier)

from sklearn.tree import DecisionTreeClassifier

# X是特征变量,共有5个训练数据,每个数据有2个特征,如数据[1,2],它的第1个特征的数值为1,第2个特征的数值为2。
X = [[1,2],[3,4],[5,6],[7,8],[9,10]]

# 目标变量,共有2个类别——0和1。
y = [1,0,0,1,1]

# 第4行代码引入模型并设置随机状态参数random_state为0
# 这里的0没有特殊含义,可换成其他数字。它是一个种子参数,可使每次运行结果一致。
model = DecisionTreeClassifier(random_state=0)

model.fit(X,y)
model.predict([[5,5]])



# 输出结果
# array([0])

可以看到,数据[5,5]被预测为类别0。

为便于理解,将决策树可视化(方法见后边),效果如下图所示,图中各个量的含义如下:

·X[0]表示数据的第1个特征;

·X[1]表示数据的第2个特征;

·gini表示该节点的基尼系数,以根节点为例,它的基尼系数为1-(0.42+0.62)=0.48;

·samples表示该节点的样本数;

·value表示各分类的样本数,例如,根节点中的[2,3]表示分类为0的样本数为2,分类为1的样本数为3;

·class表示该区块被划分为的类别,它是由value中样本数较多的类别决定的,例如,根节点中分类为1的样本数(3)大于分类为0的样本数(2),所以该节点的分类为1,依此类推。

根节点以X[1]是否小于等于7作为节点划分依据,如果满足该条件(即True),则划分到左边的子节点,否则(即False)划分到右边的子节点。以数据[5,5]为例,在根节点时,它满足X[1](即第2个特征数值)小于等于7的条件,所以被划分到左边的子节点。在该子节点又进行一次判断,判断X[0]是否小于等于2,因为X[0]为5,不满足该条件,所以划分到该子节点的右边的子节点,而该子节点的类别class为0,所以[5,5]在该决策树模型中被预测为类别0。

random_state参数的作用

决策树模型会优先选择使整个系统的基尼系数下降最大的划分方式来进行节点划分,但是有可能根据不同的划分方式获得的基尼系数下降是一样的,如果不设置random_state参数,就会导致程序每次运行时会获得不同的决策树。下图所示为不设置random_state参数时多次运行后获得的两棵不同的决策树。

可以看到,两棵决策树的节点划分方式不同,但它们产生的基尼系数下降却是一样的,均为0.48-(0.6×0.444+0.4×0)=0.2136。这两棵决策树的节点划分方式都是合理的,但对相同的数据进行预测却会得到不同的结果。例如,数据[7,7]在左边的决策树中会被预测为类别0,而在右边的决策树中会被预测为类别1。

这种现象在数据量较少时容易出现,当数据量较大时出现的概率则较小。为了避免这种现象,保证程序每次运行时都能采用相同的节点划分方式,以获得相同的决策树,就需要设置random_state参数。该参数其实是一个随机数生成器的种子,可以设置为0、1、123等任意数字。

4.2 回归决策树模型(DecisionTreeRegressor)

决策树除了能进行分类分析,还能进行回归分析,即预测连续变量,此时的决策树称为回归决策树。

回归决策树模型的简单演示代码如下。

from sklearn.tree import DecisionTreeRegressor
X = [[1,2],[3,4],[5,6],[7,8],[9,10]]
y = [1,2,3,4,5]
model = DecisionTreeRegressor(max_depth=2,random_state=0)
model.fit(X,y)
model.predict([[9,9]])


# 输出
array([4.5])

可以看到,数据[9,9]的预测拟合值为4.5。

回归决策树模型的概念和分类决策树模型基本一致,最大的不同就是其划分标准不是基尼系数或信息熵,而是均方误差MSE,其计算公式如下。

其中n为样本数量,为实际值,为拟合值。

为便于理解,将决策树可视化,如下图所示。

图中的X[0]表示数据的第1个特征,X[1]表示数据的第2个特征;mse表示该节点的均方误差;samples表示该节点的样本数;value表示该节点的拟合值,在回归决策树中,节点的拟合值是节点中所有数据的均值,最终的叶子节点的拟合值就是最终的回归模型预测值。

 举例来说,根节点中一共有5个数据,其拟合值=(1+2+3+4+5)/5=3,其均方误差MSE的计算过程如下所示,结果为2,和程序获得的结果是一致的。

回归决策树的目的是使最终系统的均方误差最小,其节点划分也是基于这个理念。上图中的根节点是根据“X[1]≤5.0”进行划分的,这使得系统的均方误差下降值最大。系统的均方误差下降值为2-(0.4×0.25+0.6×0.667)=1.5。

如果不限制决策树的深度,那么决策树将一直往下延伸,直到所有叶子节点的均方误差MSE都等于0为止。这里因为设置了树的最大深度参数max_depth为2,所以决策树在根节点往下共有2层,如果不设置这一参数,那么右下角的节点还将继续分裂,直到所有叶子节点的均方误差MSE都为0为止。

5 案例:员工离职预测模型

5.1 模型搭建

5.1.1 数据读取与预处理

“离职”列中的数字1代表离职,数字0代表未离职。

该表格共有15000组历史数据,前3571组为离职员工数据,后11429组为非离职员工数据。

目的就是根据这些历史数据搭建决策树模型来预测之后员工的离职可能性。

原始数据中的“工资”数据被分为“高”“中”“低”3个等级,而Python数学建模中无法识别这种文本内容,所以“工资”列的内容需要进行数值化处理。这里用pandas库中的replace()函数将文本“高”“中”“低”分别替换为数字2、1、0。

将表格中的“离职”列作为目标变量,剩下的字段作为特征变量,通过一个员工的特征来判断其是否会离职。

5.1.2 提取特征变量和目标变量

5.1.3 划分训练集与测试集

划分后的数据如下所示:

5.1.4 模型搭建及训练

5.1.5 代码汇总

# 1.数据读取与预处理
import pandas as pd
df = pd.read_excel('员工离职预测模型.xlsx')
df = df.replace('工资':'低':0,'中':1,'高':2)

# 2.提取特征变量与目标变量
X = df.drop(columns=['离职'])
y = df['离职']

# 3.划分训练集与测试集
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=123)

# 4.模型训练与拟合
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(max_depth=3,random_state=123)
model.fit(X_train,y_train)

5.2 模型预测及评估

5.2.1 直接预测是否离职

可以看到,测试集中前5组数据的预测准确度为100%。如果要查看整体的预测准确度,可以使用如下代码。

模型对整个测试集的预测准确度为0.9573,即在3000组测试集数据中有约2872组数据的预测结果和实际结果相符。

模型自带的score()函数来查看预测准确度。

5.2.2 预测不离职与离职的概率

分类决策树模型在本质上预测的并不是精确的0或1的分类,而是预测属于某一分类的概率。

可以通过如下代码查看预测属于各个分类的概率。

5.2.3 模型预测效果评估(ROC曲线)

对于分类模型,不仅关心预测准确度,更关心命中率(所有实际离职的员工中被预测为离职的员工所占的比率)和假警报率(所有实际不离职的员工中被预测为离职的员工所占的比率)这两个指标,并通过这两个指标绘制ROC曲线来评估模型。

在阈值相同的情况下,假警报率尽可能小,命中率尽可能高,即ROC曲线尽可能陡峭,其对应的AUC值(ROC曲线下方的面积)尽可能高。

第1行表示只有当某员工被预测为离职的概率≥100%(因为概率不会超过100%,所以其实就是被预测为离职的概率等于100%),才判定其会离职,此时命中率为24.7%,即所有实际离职的员工中被预测为离职的员工占24.7%

第2行表示只有当某员工被预测为离职的概率≥94.6%,才判定其会离职,此时命中率为67.8%,假警报率为0.82%,依此类推。

 

通过如下代码则可以快速求出模型的AUC值。

5.2.4 特征重要性评估

模型搭建完成后,有时还需要知道各个特征变量的重要程度,即哪些特征变量在模型中发挥的作用更大,这个重要程度称为特征重要性

在决策树模型中,一个特征变量对模型整体的基尼系数下降的贡献越大,它的特征重要性就越大。

通过如下代码可以查看决策树模型中各特征变量的特征重要性。

如果特征变量很多,可以使用如下代码将特征名称和特征重要性一一对应,以方便查看。

可以看到,特征重要性最高的是“满意度”,这一点的确符合常理,因为员工对工作的满意度高,其离职的概率就相对较低,反之则较高。其次重要的是“考核得分”和“工龄”。“工资”在该模型中的特征重要性为0,也就是说它没有发挥作用,这并不符合常理。之所以会有这个结果,在某种程度上是因为我们限制了决策树的最大深度为3层(max_depth=3),所以“工资”没有发挥作用的机会,如果增大决策树的最大深度,那么它可能会发挥作用。另一个更重要的原因是本案例中的“工资”不是具体的数值,而是“高”“中”“低”3个档次,这种划分方式过于宽泛,使得该特征变量在决策树模型中发挥的作用较小,如果“工资”是具体的数值,如10000元,那么该特征变量应该会发挥更大的作用。

6 参数调优

6.1 K折交叉验证

在机器学习中,因为训练集和测试集的数据划分是随机的,所以有时会重复地使用数据,以便更好地评估模型的有效性,并选出最好的模型,该做法称为交叉验证。具体而言就是对原始样本数据进行切分,然后组合成为多组不同的训练集和测试集,用训练集训练模型,用测试集评估模型。某次的训练集可能是下次的测试集,故而称为交叉验证。

交叉验证的方法有简单交叉验证、K折交叉验证和留一交叉验证3种。其中K折交叉验证应用较为广泛,它是指将数据集随机等分为K份,每次选取K-1份作为训练集,用剩下的1份作为测试集,得到K个模型后将这K个模型的平均测试效果作为最终的模型效果。

通常来说,如果训练集相对较小,则增大K值,这样在每次迭代过程中将会有更多数据用于模型训练,同时算法时间延长;如果训练集相对较大,则减小K值,这样可以降低模型在不同的数据块上进行重复拟合性能评估的计算成本,在平均性能的基础上获得模型的准确评估。

K折交叉验证的代码实现

交叉验证的函数cross_val_score()传入的参数依次为模型名称(model)、特征变量数据(X)、目标变量数据(y)、交叉验证的次数(cv)。

这里设置cv为5,表示交叉验证5次,每次随机取4/5的数据用于训练,1/5的数据用于测试。如果不设置该参数,则默认交叉验证3次。

此外,这里没有设置scoring参数,表示以默认值'accuracy'(准确度)作为评估标准。

如果想以ROC曲线的AUC值作为评估标准,则可以设置scoring参数为'roc_auc',代码如下。

6.2 GridSearch网格搜索

GridSearch网格搜索是一种穷举搜索的参数调优手段:遍历所有的候选参数,循环建立模型并评估模型的有效性和准确性,选取表现最好的参数作为最终结果。以决策树模型最大深度参数max_depth为例,我们可以在[1,3,5,7,9]这些值中遍历,以准确度或ROC曲线的AUC值作为评估标准来搜索最合适的max_depth值。如果要同时调节多个模型参数,例如,模型有2个参数,第1个参数有4种可能,第2个参数有5种可能,所有的可能性可以表示成4×5的网格,那么遍历的过程就像是在网格(Grid)里搜索(Search),这就是该方法名称的由来。

6.2.1 单参数调优

这里以单参数max_depth为例,演示机器学习中如何用网格搜索进行参数调优。

使用Scikit-Learn库中的GridSearchCV()函数对决策树模型进行参数调优,代码如下。

6.2.2 多参数调优

除了可以进行单参数调优,GridSearch网格搜索还可以进行多参数同时调优。下面选择DecisionTreeClassifier()函数的3个超参数max_depth(最大深度)、criterion(特征选择标准)和min_samples_split(子节点往下分裂所需的最小样本数),使用GridSearchCV()函数进行多参数调优,代码如下。

从输出结果可知,将criterion设置为'entropy'(信息熵)、max_depth设置为11、min_samples_split设置为13时,模型最优。将这些参数的最优值引入模型,代码如下。

注意:

第一,多参数调优和单参数分别调优是有区别的。不能为了省事,对多个参数分别进行单参数调优,然后将结果汇总,这种做法是不严谨的。因为在进行单参数调优时,其他参数会取默认值,那么就忽略了该参数和其他参数都不取默认值的情况,即忽略了多个参数对模型的组合影响。以上述代码示例来说,进行多参数调优时,有5×2×6=60种可能的组合,而进行3次单参数调优时,则只有5+2+6=13种可能的组合。因此,如果只需要调节一个参数,那么可以进行单参数调优,如果需要调节多个参数,则推荐进行多参数调优。

第二,如果使用GridSearchCV()函数得到的参数最优值是给定范围的边界值,那么有可能存在范围以外的值使得模型效果更好,此时需要额外增大范围,继续进行参数调优。举例来说,倘若上述代码获得的max_depth最优值为设定的最大值13,那么真正的max_depth最优值可能更大,此时便需要重新调整搜索网格,如将max_depth的搜索范围变成[9,11,13,15,17],再重新进行参数调优。

补充知识点:决策树的前剪枝和后剪枝

决策树剪枝的目的是防止构建的决策树出现过拟合。决策树剪枝分为前剪枝和后剪枝,两者的定义如下。

·前剪枝:从上往下剪枝,通常利用超参数进行剪枝。例如,通过限制树的最大深度(max_depth)便能剪去该最大深度下面的节点。

·后剪枝:从下往上剪枝,大多是根据业务需求剪枝。例如,在违约预测模型中,认为违约概率为45%和50%的两个叶子节点都是高危人群,那么就把这两个叶子节点合并成一个节点。

在商业实战中,前剪枝应用得更广泛,参数调优其实也起到了一定的前剪枝作用。

补充知识点:分类决策树模型DecisionTreeClassifier()的常用超参数

·criterion:特征选择标准,取值为'entropy'(信息熵)和'gini'(基尼系数),默认值为'gini'。

·splitter:取值为'best'和'random'。'best'指在特征的所有划分点中找出最优的划分点,适合样本量不大的情况;'random'指随机地在部分划分点中寻找局部最优的划分点,适合样本量非常大的情况;默认值为'best'。

·max_depth:决策树最大深度,取值为int型数据或None,默认值为None。一般数据或特征较少时可以不设置,如果数据或特征较多,可以设置最大深度进行限制。

·min_samples_split:子节点往下分裂所需的最小样本数,默认值为2。如果子节点中的样本数小于该值则停止分裂。

·min_samples_leaf:叶子节点的最小样本数,默认值为1。如果叶子节点中的样本数小于该值,该叶子节点会和兄弟节点一起被剪枝,即剔除该叶子节点和其兄弟节点,并停止分裂。

·min_weight_fraction_leaf:叶子节点最小的样本权重和,默认值为0,即不考虑权重问题。如果小于该值,该叶子节点会和兄弟节点一起被剪枝。如果较多样本有缺失值或者样本的分布类别偏差很大,则需考虑样本权重问题。

·max_features:在划分节点时所考虑的特征值数量的最大值,默认值为None,可以传入int型或float型数据,如果传入的是float型数据,则表示百分数。

·max_leaf_nodes:最大叶子节点数,默认值为None,可以传入int型数据。

·class_weight:指定类别权重,默认值为None,可以取'balanced',代表样本量少的类别所对应的样本权重更高,也可以传入字典来指定权重。该参数主要是为防止训练集中某些类别的样本过多,导致训练的决策树过于偏向这些类别。除了指定该参数,还可以使用过采样和欠采样的方法处理样本类别不平衡的问题。

·random_state:当数据量较大或特征变量较多,可能在某个节点划分时,会遇到两个特征变量的信息增益或基尼系数下降值相同的情况,此时决策树模型默认会从中随机选择一个特征变量进行划分,这样可能会导致每次运行程序后生成的决策树不一致。设置random_state参数(如设置为123)可以保证每次运行程序后各节点的分裂结果都是一致的,这在特征变量较多、树的深度较深时较为重要。

补充知识点:树模型在金融大数据风控领域的应用 

以决策树为代表的树模型在金融大数据风控领域也有很大的应用空间。以银行的信贷违约预测模型为例,通常会用到逻辑回归模型和决策树模型。

逻辑回归模型不需要太多变量,不容易过拟合,泛化能力较强,可能一年才需要换一次模型,但是有时不够精确,不能有效剔除潜在违约人员。树模型(决策树、随机森林、XGBoost等模型)不太稳定(一个变量可以反复用),容易造成过拟合,泛化能力较弱,一段时间后换一批人可能就不行了,但拟合度强,区分度高,可以快速去掉违约人员。

因此,商业实战中常以基于逻辑回归的评分卡模型为基础(稳定性强,半年到一年更新一次,但不够精确,KS值不够大),再结合决策树等树模型(不太稳定,可能要一个月更新一次,但拟合度强,区分度高,可以在第一拨快速去掉违约人员)。

总结来说,作为机器学习的经典算法模型,决策树模型具有独特的优势,如对异常值不敏感、可解释性强等,不过它也有一些缺点,如结果不稳定、容易造成过拟合等。更重要的是,决策树模型是很多重要集成模型的基础,如随机森林模型、AdaBoost模型、GBDT模型、XGBoost与LightGBM模型都是建立在决策树模型的基础上的。

参考书籍

《Python大数据分析与机器学习商业案例实战》

以上是关于决策树模型及案例(Python)的主要内容,如果未能解决你的问题,请参考以下文章

机器学习树模型决策的可解释性与微调(Python)

机器学习树模型决策的可解释性与微调(Python)

Python机器学习及实践 课后小题

Machine Learn决策树案例:基于python的商品购买能力预测系统

基于Python实现的决策树模型

python_机器学习_监督学习模型_决策树