【sklearn】1.分类决策树

2022-06-14 11:53:22 浏览数 (1)

前言

决策树是机器学习中的一种常用算法。相关数学理论我也曾在数学建模专栏中数学建模学习笔记(二十五)决策树 介绍过,本篇博文不注重相关数学原理,主要注重使用sklearn实现分类树的效果。 参考课程见【2020机器学习全集】菜菜的sklearn完整版

决策树简介

决策树(Decision Tree)是一种非参数的有监督学习方法,它能够从一系列有特征和标签的数据中总结出决策规则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。

sklearn中的决策树

  • 模块sklearn.tree

树类型

库表示

分类树

tree.DecisionTreeClassifier

回归树

tree.DecisionTreeRegressor

生成的决策树导出为DOT格式,画图专用

tree.export_graphviz

高随机版本的分类树

tree.ExtraTreeClassifier

高随机版本的回归树

tree.ExtraTreeRegressor

sklearn的基本建模流程

对应python代码

代码语言:javascript复制
from sklearn import tree #导入需要的模块

clf = tree.DecisionTreeClassifier()     #实例化
clf = clf.fit(X_train,y_train) #用训练集数据训练模型
result = clf.score(X_test,y_test) #导入测试集,从接口中调用需要的信息

分类树 DecisionTreeClassifier

重要参数

criterion 决定不纯度的计算方法

为了要将表格转化为一棵树,决策树需要找出最佳节点和最佳的分枝方法,对分类树来说,衡量这个“最佳”的指标叫做“不纯度”。通常来说,不纯度越低,决策树对训练集的拟合越好。 通俗理解:为了将一群混在一起的复杂样本分开,用不纯度来进行衡量,没分之前,也就是根节点,不纯度最高,之后越往下面不纯度越低,到叶子节点,就完全分离开,不纯度最低,得到的结果最“纯净”!

Criterion这个参数正是用来决定不纯度的计算方法的。sklearn提供了两种选择: 1)输入”entropy“,使用信息熵(Entropy) 2)输入”gini“,使用基尼系数(Gini Impurity)

不填写,默认的是gini。 sklearn实际计算的是基于信息熵的信息增益(Information Gain),即父节点的信息熵和子节点的信息熵之差。

选取规则: 通常就使用基尼系数 数据维度很大,噪音很大时使用基尼系数 维度低,数据比较清晰的时候,信息熵和基尼系数没区别 当决策树的拟合程度不够的时候,使用信息熵 两个都试试,不好就换另外一个

建立分类树步骤

1.导入需要的算法库和模块

代码语言:javascript复制
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
import pandas as pd
import graphviz

2.查看数据 这里使用的是sklearn自带的wine数据集。

代码语言:javascript复制
wine = load_wine()
print(wine.data.shape)

print(pd.concat([pd.DataFrame(wine.data), pd.DataFrame(wine.target)], axis=1))
print(wine.feature_names)
print(wine.target_names)

总共178条数据,3分类问题。

3.划分训练集和测试集

代码语言:javascript复制
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
print(Xtrain.shape)
print(Xtest.shape)

test_size=0.3表示测试集占样本数量的30%

划分之后,训练集为124条数据,测试集为54条数据。

4.模型建立

代码语言:javascript复制
clf = tree.DecisionTreeClassifier(criterion="entropy")
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) # 返回预测的准确度
print(score)

这里选用信息熵entropy作为计算方法。 score代表准确度 由于决策树的建立包含随机变量,每次运行结果都不一样。 这里我运行几次大致结果准确率在90%以上。

5.决策树可视化

代码语言:javascript复制
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸']

dot_data = tree.export_graphviz(clf
                               ,feature_names= feature_name
                               ,class_names=["类型一","类型二","类型三"]
                               ,filled=True  #控制颜色填充
                               ,rounded=True  #控制图片为圆角
                               )
graph = graphviz.Source(dot_data.replace('helvetica','"Microsoft YaHei"'), encoding='utf-8')
graph.view()

这里直接运行会报错,问题是虽然安装了graphviz库,但仍需安装graphviz插件才能显示图片。 插件下载地址https://graphviz.gitlab.io/download/ windows选择:

在安装时,勾选将graphviz添加到环境变量

replace(‘helvetica’,’“Microsoft YaHei”’), encoding='utf-8’目的是防止中文乱码,使用utf-8进行重新编码。

运行之后,会直接打开一张pdf图片。

这就是分类决策树,每一个分支节点上第一行代表分支的依据。 颜色代表不纯度,颜色越深代表代表不纯度越小,叶子节点不纯度为0。

6.特征重要性显示 上图的决策树分支是根据特征重要性(信息增益)来进行分支,通过下面的程序可以打印出各个特征的重要性。

代码语言:javascript复制
print([*zip(feature_name,clf.feature_importances_)])

得到结果:

代码语言:javascript复制
[('酒精', 0.0), ('苹果酸', 0.0), ('灰', 0.0), ('灰的碱性', 0.03448006546085971), ('镁', 0.0), ('总酚', 0.0), ('类黄酮', 0.4207777417026953), ('非黄烷类酚类', 0.0), ('花青素', 0.0), ('颜色强度', 0.1444829682905809), ('色调', 0.03408453152321241), ('od280/od315稀释葡萄酒', 0.0), ('脯氨酸', 0.3661746930226517)]

有些特征的重要性为0,说明这些指标在决策树中没有被利用。

随机参数 random_state & splitter

在上面的例子中,每次运行结果都会有些不同,原因在于使用sklearn自带的决策树时,它会默认“栽种”好几棵不同的决策树,从中返回出效果最好的那一棵。

random_state用来设置分枝中的随机模式的参数,默认None,输入任意整数,会一直长出同一棵树,让模型稳定下来。

splitter也是用来控制决策树中的随机选项的,有两种输入值:

  • 输入”best",决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝(重要性可以通过属性feature_importances_查看)
  • 输入“random",决策树在分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。这也是防止过拟合的一种方式。
代码语言:javascript复制
clf = tree.DecisionTreeClassifier(criterion="entropy"
                                 ,random_state=30
                                 ,splitter="random"
                                 )

设置随机参数可以让决策树稳定或者更随机,效果不确定,一切以最后的score为主。

剪枝策略 max_depth

max_depth 用来限制树的最大深度,超过设定深度的树枝全部剪掉 策树多生长一层,对样本量的需求会增加一倍。 实际使用时,建议从=3开始尝试,看看拟合的效果再决定是否增加设定深度。

剪枝策略 min_samples_leaf & min_samples_split

min_samples_leaf限定,一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分 枝就不会发生,一般来说,建议从=5开始使用。

min_samples_split限定,一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝,否则 分枝就不会发生。

代码语言:javascript复制
clf = tree.DecisionTreeClassifier(criterion="entropy"
                                 ,random_state=30
                                 ,splitter="random"
                                 ,max_depth=3
                                 ,min_samples_leaf=10
                                 ,min_samples_split=10
                                 )

剪枝策略max_features & min_impurity_decrease

max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃。

min_impurity_decrease限制信息增益的大小,信息增益小于设定数值的分枝不会发生。

确认最优的剪枝参数

通过编程循环,控制其它量不变,一个量循环改变,画图显示,可以显示出这个量的最优值。

下面以max_depth为例:

代码语言:javascript复制
import matplotlib.pyplot as plt

test = []
for i in range(10):
    clf = tree.DecisionTreeClassifier(max_depth=i 1
                                     ,criterion="entropy"
                                     ,random_state=30
                                     ,splitter="random"
                                     )
    clf = clf.fit(Xtrain, Ytrain)
    score = clf.score(Xtest, Ytest)
    test.append(score)
plt.plot(range(1,11),test,color="red",label="max_depth")
plt.legend()
plt.show()

绘制结果如图所示

说明max_depth取4时,效果最好。

目标权重参数class_weight & min_weight_fraction_leaf

想象这种情况:在银行要判断“一个办了信用卡的人是否会违约”,就是 是vs否(1%:99%)的比例,在这种情况下,出现了样本不平衡,这个时候就需要调整其目标权重参数。

使用class_weight参数对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少数类,向捕获少数类的方向建模。该参数默认None,此模式表示自动给与数据集中的所有标签相同的权重。

有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,因此这时候剪枝,就需要搭配min_weight_fraction_leaf这个基于权重的剪枝参数来使用。

重要属性和接口

1.(上面提到过)feature_importances_ 能够查看各个特征对模型的重要性 注意后面的下划线_不能省略

2.apply 返回每个测试样本所在的叶子节点的索引

代码语言:javascript复制
clf.apply(Xtest)

3.predict返回每个测试样本的分类/回归结果

代码语言:javascript复制
clf.predict(Xtest)

其它内容补充

分类树天生不擅长环形数据,最擅长月亮型数据的是最近邻算法,RBF支持向量机和高斯过程;最擅长环形数据的是最近邻算法和高斯过程;最擅长对半分的数据的是朴素贝叶斯,神经网络和随机森林。

上面是分类树的结果,环形数据可以看到左侧出现一块白色,说明分类效果不好。

0 人点赞