1 逻决策树的介绍和应用
1.1 决策树的介绍
决策树是一种常见的分类模型,在金融风控、医疗辅助诊断等诸多行业具有较为广泛的应用。决策树的核心思想是基于树结构对数据进行划分,这种思想是人类处理问题时的本能方法。例如在婚恋市场中,女方通常会先询问男方是否有房产,如果有房产再了解是否有车产,如果有车产再看是否有稳定工作……最后得出是否要深入了解的判断。
决策树的主要优点:
具有很好的解释性,模型可以生成可以理解的规则。
可以发现特征的重要程度。
模型的计算复杂度较低。
决策树的主要缺点:
模型容易过拟合,需要采用减枝技术处理。
不能很好利用连续型特征。
预测能力有限,无法达到其他强监督模型效果。
方差较高,数据分布的轻微改变很容易造成树结构完全不同。
1.2 决策树的应用
由于决策树模型中自变量与因变量的非线性关系以及决策树简单的计算方法,使得它成为集成学习中最为广泛使用的基模型。梯度提升树(GBDT),XGBoost以及LightGBM等先进的集成模型都采用了决策树作为基模型,在广告计算、CTR预估、金融风控等领域大放异彩,成为当今与神经网络相提并论的复杂模型,更是数据挖掘比赛中的常客。在新的研究中,南京大学周志华教授提出一种多粒度级联森林模型,创造了一种全新的基于决策树的深度集成方法,为我们提供了决策树发展的另一种可能。
同时决策树在一些明确需要可解释性或者提取分类规则的场景中被广泛应用,而其他机器学习模型在这一点很难做到。例如在医疗辅助系统中,为了方便专业人员发现错误,常常将决策树算法用于辅助病症检测。例如在一个预测哮喘患者的模型中,医生发现测试的许多高级模型的效果非常差。在他们运行了一个决策树模型后发现,算法认为剧烈咳嗽的病人患哮喘的风险很小。但医生非常清楚剧烈咳嗽一般都会被立刻检查治疗,这意味着患有剧烈咳嗽的哮喘病人都会马上得到收治。用于建模的数据认为这类病人风险很小,是因为所有这类病人都得到了及时治疗,所以极少有人在此之后患病或死亡。
2. 实验室手册
2.1 学习目标
了解 决策树 的理论知识
掌握 决策树 的 sklearn 函数调用并将其运用在企鹅数据集的预测中
2.2 代码流程
Part1 Demo实践
Step1:库函数导入
Step2:模型训练
Step3:数据和模型可视化
Step4:模型预测
Part2 基于企鹅(penguins)数据集的决策树分类实践
Step1:库函数导入
Step2:数据读取/载入
Step3:数据信息简单查看
Step4:可视化描述
Step5:利用 决策树模型 在二分类上 进行训练和预测
Step6:利用 决策树模型 在三分类(多分类)上 进行训练和预测
2.3 算法实战
2.3.1 Demo实践
Step1: 库函数导入
1 2 3 4 5 6 7 8 9 10 import numpy as np import matplotlib.pyplot as pltimport seaborn as snsfrom sklearn.tree import DecisionTreeClassifierfrom sklearn import tree
Step2:模型训练
1 2 3 4 5 6 7 8 9 10 11 x_fearures = np.array([[-1 , -2 ], [-2 , -1 ], [-3 , -2 ], [1 , 3 ], [2 , 1 ], [3 , 2 ]]) y_label = np.array([0 , 1 , 0 , 1 , 0 , 1 ]) tree_clf = DecisionTreeClassifier() tree_clf = tree_clf.fit(x_fearures, y_label)
Step3:数据和模型可视化
1 2 3 4 5 plt.figure() plt.scatter(x_fearures[:,0 ],x_fearures[:,1 ], c=y_label, s=50 , cmap='viridis' ) plt.title('Dataset' ) plt.show()
Step4:模型预测
1 2 3 4 5 6 7 8 9 10 x_fearures_new1 = np.array([[0 , -1 ]]) x_fearures_new2 = np.array([[2 , 1 ]]) y_label_new1_predict = tree_clf.predict(x_fearures_new1) y_label_new2_predict = tree_clf.predict(x_fearures_new2) print ('The New point 1 predict class:\n' ,y_label_new1_predict)print ('The New point 2 predict class:\n' ,y_label_new2_predict)
The New point 1 predict class:
[1]
The New point 2 predict class:
[0]
2.3.2 基于企鹅数据集的决策树实战
在实践的最开始,我们首先需要导入一些基础的函数库包括:numpy (Python进行科学计算的基础软件包),pandas(pandas是一种快速,强大,灵活且易于使用的开源数据分析和处理工具),matplotlib和seaborn绘图。
1 2 !wget https://tianchi-media.oss-cn-beijing.aliyuncs.com/DSW/6tree/penguins_raw.csv
1 2 3 4 5 6 7 import numpy as np import pandas as pdimport matplotlib.pyplot as pltimport seaborn as sns
本次我们选择企鹅数据(palmerpenguins)进行方法的尝试训练,该数据集一共包含8个变量,其中7个特征变量,1个目标分类变量。共有150个样本,目标变量为 企鹅的类别 其都属于企鹅类的三个亚属,分别是(Adélie, Chinstrap and Gentoo)。包含的三种种企鹅的七个特征,分别是所在岛屿,嘴巴长度,嘴巴深度,脚蹼长度,身体体积,性别以及年龄。
变量
描述
species
a factor denoting penguin species
island
a factor denoting island in Palmer Archipelago, Antarctica
bill_length_mm
a number denoting bill length
bill_depth_mm
a number denoting bill depth
flipper_length_mm
an integer denoting flipper length
body_mass_g
an integer denoting body mass
sex
a factor denoting penguin sex
year
an integer denoting the study year
1 2 3 data = pd.read_csv('./penguins_raw.csv' )
1 2 3 data = data[['Species' ,'Culmen Length (mm)' ,'Culmen Depth (mm)' , 'Flipper Length (mm)' ,'Body Mass (g)' ]]
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 344 entries, 0 to 343
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Species 344 non-null object
1 Culmen Length (mm) 342 non-null float64
2 Culmen Depth (mm) 342 non-null float64
3 Flipper Length (mm) 342 non-null float64
4 Body Mass (g) 342 non-null float64
dtypes: float64(4), object(1)
memory usage: 13.6+ KB
Species
Culmen Length (mm)
Culmen Depth (mm)
Flipper Length (mm)
Body Mass (g)
0
Adelie Penguin (Pygoscelis adeliae)
39.1
18.7
181.0
3750.0
1
Adelie Penguin (Pygoscelis adeliae)
39.5
17.4
186.0
3800.0
2
Adelie Penguin (Pygoscelis adeliae)
40.3
18.0
195.0
3250.0
3
Adelie Penguin (Pygoscelis adeliae)
NaN
NaN
NaN
NaN
4
Adelie Penguin (Pygoscelis adeliae)
36.7
19.3
193.0
3450.0
这里我们发现数据集中存在NaN,一般的我们认为NaN在数据集中代表了缺失值,可能是数据采集或处理时产生的一种错误。这里我们采用-1将缺失值进行填补,还有其他例如“中位数填补、平均数填补”的缺失值处理方法有兴趣的同学也可以尝试。
1 2 data = data.fillna(-1 ) data.tail()
Species
Culmen Length (mm)
Culmen Depth (mm)
Flipper Length (mm)
Body Mass (g)
339
Chinstrap penguin (Pygoscelis antarctica)
55.8
19.8
207.0
4000.0
340
Chinstrap penguin (Pygoscelis antarctica)
43.5
18.1
202.0
3400.0
341
Chinstrap penguin (Pygoscelis antarctica)
49.6
18.2
193.0
3775.0
342
Chinstrap penguin (Pygoscelis antarctica)
50.8
19.0
210.0
4100.0
343
Chinstrap penguin (Pygoscelis antarctica)
50.2
18.7
198.0
3775.0
1 2 3 data['Species' ].unique()
array(['Adelie Penguin (Pygoscelis adeliae)',
'Gentoo penguin (Pygoscelis papua)',
'Chinstrap penguin (Pygoscelis antarctica)'], dtype=object)
1 2 pd.Series(data['Species' ]).value_counts()
Adelie Penguin (Pygoscelis adeliae) 152
Gentoo penguin (Pygoscelis papua) 124
Chinstrap penguin (Pygoscelis antarctica) 68
Name: Species, dtype: int64
Culmen Length (mm)
Culmen Depth (mm)
Flipper Length (mm)
Body Mass (g)
count
344.000000
344.000000
344.000000
344.000000
mean
43.660756
17.045640
199.741279
4177.319767
std
6.428957
2.405614
20.806759
861.263227
min
-1.000000
-1.000000
-1.000000
-1.000000
25%
39.200000
15.500000
190.000000
3550.000000
50%
44.250000
17.300000
197.000000
4025.000000
75%
48.500000
18.700000
213.000000
4750.000000
max
59.600000
21.500000
231.000000
6300.000000
1 2 3 sns.pairplot(data=data, diag_kind='hist' , hue= 'Species' ) plt.show()
从上图可以发现,在2D情况下不同的特征组合对于不同类别的企鹅的散点分布,以及大概的区分能力。Culmen Lenth与其他特征的组合散点的重合较少,所以对于数据集的划分能力最好。
我们发现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 '''为了方便我们将标签转化为数字 'Adelie Penguin (Pygoscelis adeliae)' ------0 'Gentoo penguin (Pygoscelis papua)' ------1 'Chinstrap penguin (Pygoscelis antarctica) ------2 ''' def trans (x ): if x == data['Species' ].unique()[0 ]: return 0 if x == data['Species' ].unique()[1 ]: return 1 if x == data['Species' ].unique()[2 ]: return 2 data['Species' ] = data['Species' ].apply(trans)
1 2 3 4 5 for col in data.columns: if col != 'Species' : sns.boxplot(x='Species' , y=col, saturation=0.5 , palette='pastel' , data=data) plt.title(col) plt.show()
利用箱型图我们也可以得到不同类别在不同特征上的分布差异情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from mpl_toolkits.mplot3d import Axes3Dfig = plt.figure(figsize=(10 ,8 )) ax = fig.add_subplot(111 , projection='3d' ) data_class0 = data[data['Species' ]==0 ].values data_class1 = data[data['Species' ]==1 ].values data_class2 = data[data['Species' ]==2 ].values ax.scatter(data_class0[:,0 ], data_class0[:,1 ], data_class0[:,2 ],label=data['Species' ].unique()[0 ]) ax.scatter(data_class1[:,0 ], data_class1[:,1 ], data_class1[:,2 ],label=data['Species' ].unique()[1 ]) ax.scatter(data_class2[:,0 ], data_class2[:,1 ], data_class2[:,2 ],label=data['Species' ].unique()[2 ]) plt.legend() plt.show()
Step5:利用 决策树模型 在二分类上 进行训练和预测
1 2 3 4 5 6 7 8 9 10 11 12 13 from sklearn.model_selection import train_test_splitdata_target_part = data[data['Species' ].isin([0 ,1 ])][['Species' ]] data_features_part = data[data['Species' ].isin([0 ,1 ])][['Culmen Length (mm)' , 'Culmen Depth (mm)' , 'Flipper Length (mm)' ,'Body Mass (g)' ]] x_train, x_test, y_train, y_test = train_test_split(data_features_part, data_target_part, test_size = 0.2 , random_state = 2020 )
1 2 3 4 5 6 7 from sklearn.tree import DecisionTreeClassifierfrom sklearn import treeclf = DecisionTreeClassifier(criterion='entropy' ) clf.fit(x_train, y_train)
DecisionTreeClassifier(criterion='entropy')
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 train_predict = clf.predict(x_train) test_predict = clf.predict(x_test) from sklearn import metricsprint ('The accuracy of the Logistic Regression is:' ,metrics.accuracy_score(y_train,train_predict))print ('The accuracy of the Logistic Regression is:' ,metrics.accuracy_score(y_test,test_predict))confusion_matrix_result = metrics.confusion_matrix(test_predict,y_test) print ('The confusion matrix result:\n' ,confusion_matrix_result)plt.figure(figsize=(8 , 6 )) sns.heatmap(confusion_matrix_result, annot=True , cmap='Blues' ) plt.xlabel('Predicted labels' ) plt.ylabel('True labels' ) plt.show()
The accuracy of the Logistic Regression is: 0.9954545454545455
The accuracy of the Logistic Regression is: 1.0
The confusion matrix result:
[[31 0]
[ 0 25]]
我们可以发现其准确度为1,代表所有的样本都预测正确了。
Step6:利用 决策树模型 在三分类(多分类)上 进行训练和预测
1 2 3 4 5 6 7 x_train, x_test, y_train, y_test = train_test_split(data[['Culmen Length (mm)' ,'Culmen Depth (mm)' , 'Flipper Length (mm)' ,'Body Mass (g)' ]], data[['Species' ]], test_size = 0.2 , random_state = 2020 ) clf = DecisionTreeClassifier() clf.fit(x_train, y_train)
DecisionTreeClassifier()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 train_predict = clf.predict(x_train) test_predict = clf.predict(x_test) train_predict_proba = clf.predict_proba(x_train) test_predict_proba = clf.predict_proba(x_test) print ('The test predict Probability of each class:\n' ,test_predict_proba)print ('The accuracy of the Logistic Regression is:' ,metrics.accuracy_score(y_train,train_predict))print ('The accuracy of the Logistic Regression is:' ,metrics.accuracy_score(y_test,test_predict))
The test predict Probability of each class:
[[0. 0. 1.]
[0. 1. 0.]
[0. 1. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 0. 1.]
[0. 0. 1.]
[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[0. 1. 0.]
[0. 1. 0.]
[1. 0. 0.]
[0. 1. 0.]
[0. 1. 0.]
[0. 1. 0.]
[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 0. 1.]
[1. 0. 0.]
[0. 0. 1.]
[1. 0. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 0. 1.]
[0. 0. 1.]
[0. 1. 0.]
[1. 0. 0.]
[0. 1. 0.]
[0. 1. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 0. 1.]
[0. 0. 1.]
[1. 0. 0.]
[1. 0. 0.]
[0. 1. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 1. 0.]
[0. 1. 0.]
[0. 0. 1.]
[0. 0. 1.]
[0. 1. 0.]
[1. 0. 0.]
[1. 0. 0.]
[1. 0. 0.]
[0. 1. 0.]
[0. 1. 0.]
[0. 0. 1.]
[0. 0. 1.]
[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]
[1. 0. 0.]
[1. 0. 0.]]
The accuracy of the Logistic Regression is: 0.9963636363636363
The accuracy of the Logistic Regression is: 0.9710144927536232
1 2 3 4 5 6 7 8 9 10 confusion_matrix_result = metrics.confusion_matrix(test_predict,y_test) print ('The confusion matrix result:\n' ,confusion_matrix_result)plt.figure(figsize=(8 , 6 )) sns.heatmap(confusion_matrix_result, annot=True , cmap='Blues' ) plt.xlabel('Predicted labels' ) plt.ylabel('True labels' ) plt.show()
The confusion matrix result:
[[31 1 0]
[ 0 23 0]
[ 1 0 13]]
2.4 重要知识点
2.4.3 重要参数
2.4.3.1 criterion
Criterion这个参数正是用来决定模型特征选择的计算方法的。sklearn提供了两种选择:
输入”entropy“,使用信息熵(Entropy)
输入”gini“,使用基尼系数(Gini Impurity)
2.4.3.2 random_state & splitter
random_state用来设置分枝中的随机模式的参数,默认None,在高维度时随机性会表现更明显。splitter也是用来控制决策树中的随机选项的,有两种输入值,输入”best",决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝(重要性可以通过属性feature_importances_查看),输入“random",决策树在分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。
2.4.3.3 max_depth
限制树的最大深度,超过设定深度的树枝全部剪掉。这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合。
2.4.3.4 min_samples_leaf
min_samples_leaf 限定,一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,或者,分枝会朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生。一般搭配max_depth使用,在回归树中有神奇的效果,可以让模型变得更加平滑。这个参数的数量设置得太小会引起过拟合,设置得太大就会阻止模型学习数据。