目录
一、什么是决策树
二、怎么使用决策树解决分类问题
1、重要参数
(1)Criterion
(2)random_state
(3)splitter
(4) 剪枝参数
(5)目标权重参数
2、重要接口
3、重要属性
三、决策树的优缺点以及适用场景
四、代码
使用原因:python可以实现算法,但是比较复杂,耗时耗力,而且对于程序员能力要求很高,可能会出现费力构建的模型稳定性不够或出现其他问题。而这一工作,sklearn帮我们做了,它是一个可以帮我们在操作数据处理数据的时候高效实现算法应用的工具包,使用简单。
简介:scikit-learn,又写作sklearn,是一个开源的基于python语言的机器学习工具包。它通过NumPy, SciPy和Matplotlib等python数值计算的库实现高效的算法应用,并且涵盖了几乎所有主流机器学习算法。
https://scikit-learn.org/stable/index.htmlhttps://scikit-learn.org/stable/index.html
scikit-learn中文社区Scikit-learn(以前称为scikits.learn,也称为sklearn)是针对Python 编程语言的免费软件机器学习库。它具有各种分类,回归和聚类算法,包括支持向量机,随机森林,梯度提升,k均值和DBSCAN。Scikit-learn 中文文档由CDA数据科学研究院翻译,扫码关注获取更多信息。https://scikit-learn.org.cn/以上链接为sklearn的官方教程,英文版和中文版可以对照查看。
其中,常用的模块共有六大类:分类、回归、聚类、降维、模型选择和预处理。
那今天,我们先从分类说起。
分类,顾名思义,就是将一系列的数据进行分类,可以是二分类,也可以是多分类,具体要看我们解决什么问题,预测什么内容。比如我是生物信息方向,预测氨基酸突变是否致病,那这就是一个二分类问题啦(致病or不致病)。
今天的重点是决策树,那就以决策树展开以解决分类问题,主要内容分为什么是决策树,怎么使用决策树解决分类问题以及决策树的优缺点以及适用情况,最后是代码部分。
决策树(DTs)是一种用于分类和回归的非参数有监督学习方法。其目标是创建一个模型,通过学习从数据特性中推断出的简单决策规则来预测目标变量的值。
构建决策树其实就是将数据表通过对特征提问的方式绘制为树,最终的叶节点就是我们想要的分类结果,如下图所示。
在这里,补充节点的相关概念:
根节点:只出不进
中间节点:有进有出
叶子节点:只进不出,每个叶节点都是一个类别标签
子节点和父节点:两个相连的节点中,更接近根的节点就是父节点,另一个是子节点
决策树构建的核心有两点:
在sklearn中,共有五个关于决策树的类:
Tree.DecisionTreeClassfier 分类树
Tree.DecisionTreeRegressor 回归树
Tree.export_graphviz 将生成的决策树导出为dot格式,画图专用
Tree.ExtraTreeClassifier 高随机版本的分类树
Tree.ExtraTreeRegressor 高随机版本的回归树
其实,很简单,四行搞定
from sklearn import tree
clf = tree.DecisionTreeClassifier() #实例化
clf = clf.fit(xtrain,ytrain) #训练
result = clf.score(xtest,ytest) #为测试集打分
我们可以看到在实例化一行中,括号内并无内容,但不代表无参数,而是默认了,那怎么调参呢,该怎么调呢,我们往下看。
上文已经说明了决策树的核心之一就是找出最佳的节点和最佳的分支,这就涉及到不纯度的计算。此参数就决定了怎么计算不纯度,两种方式:gini:基尼系数(默认);entropy:信息熵。
t代表给定的节点,i代表标签的任意分类,p(i,t)代表标签分类i在节点t上所占的比例。
两个的对比:
差别不大,但是信息熵会慢一些,且对不纯度会更加敏感,所以决策树会更加精细。对于高维数据和噪音过多的数据信息熵很容易过拟合,建议基尼系数,当然也不是绝对的。
具体如何选取:
在建树的过程中,是依靠优化节点来追求一棵优化的树,但最优的节点不一定保证最优的树。所以,在sklearn中,会建更多的树从中取最好的。在每次分枝时,不从全部特征中选取,而是随机从中选取一部分特征,从中选取不纯度相关指标达到最优的作为分枝用的节点。
可以设置任意整数,目的是让指标更优秀。
控制决策树的随机性。
输入值:best(选择重要性更高的特征)和 random(随机选择,可以防止过拟合)
实际情况中,常常会过拟合,也就是训练集上表现非常好,而测试集上表现一般,需要剪枝。
剪枝策略对决策树的影响较大,正确的剪枝是优化决策树算法的核心。
max_depth:特征多,但数据少,限制树的深度可以防止过拟合,建议从3开始尝试
min_samples_leaf 和 min_samples_split:限制叶子节点,可以整数,也可以是浮点数(百分比),搭配max_depth使用,建议从5开始尝试,一般情况,对于类别不多的分类问题,最佳是1。
max_features:限制考虑的特征数,超过限制个数的特征会被舍弃(不太推荐,太暴力,可以选择PCA降维或者sklearn自带的特征选择)
min_impurity_decrease:限制信息增益的大小,信息增益小于设定值分枝就不会发生
如何找出最优秀的剪枝参数?
绘制超参数曲线(详见后文代码)
当然,剪枝后,效果不一定会更好。只是当数据集较大,特征较多时,树枝的无限生长会对内存消耗很大,所以需要提前剪枝处理。
Class_weight 和 Min_weight_fraction_leaf:完成样本标签平衡的参数。默认值为None,即相同的权重。
样本标签不平衡,指的是在一个数据集中,某一类样本占有大多数,比如银行贷款违约的人数,大概百分之97的人不会违约,但是这样的数据集会导致最终模型的预测只要预测为不会违约,也会有97%的正确率,因此需要Class_weight参数对样本标签进行一定的衡量,给少量的标签更多的权重,让模型偏向于样本较少的那一类。
fit(xtrain,ytrain) 训练模型
score(xtest,ytest) 得分
predict(xtest) 返回每个测试样本的分类或者回归的结果
apply(xtest) 返回每个测试样本所在的叶子的索引
predict_proba(xtest) 预测的分类结果属于每个标签的概率值
输入的xtrain和xtest必须是二维矩阵,不接受任何一维特征矩阵,如果是一维,需要reshape(-1,1)转换。
feature_importances_ :特征重要性
#重要性
importance = clf.feature_importances_
feature_importance = [(feature,importance.round(3)) for feature,importance in zip(feature_name,importance)]
#排序
feature_importance = sorted(feature_importance,key=lambda x :x[1],reverse=True)
#对应进行打印
[print('variable:{:20} importance: {}'.format(*pair)) for pair in feature_importance]
决策树的一些优点:
易于理解和解释。树可以被可视化。
几乎不需要数据准备。其他算法通常需要数据标准化,需要创建虚拟变量并删除缺失值。但是,请注意,此模块不支持缺失值。
使用树的成本(即预测数据)是用于训练树的数据点数的对数。
能够处理数值型和分类型数据。其他技术通常专门分析只有一种类型变量的数据集。有关更多信息,请参见algorithms 。
能够处理多输出问题。
使用白盒模型。如果给定的情况在模型中是可以观察到的,那么对条件的解释就很容易用布尔逻辑来解释。相反,在黑箱模型中(例如,在人工神经网络中),结果可能很难解释。
可以使用统计测试验证模型。这样就有可能对模型的可靠性作出解释。
即使它的假设在某种程度上被生成数据的真实模型所违背,它也表现得很好。
决策树的缺点包括:
决策树学习器可以创建过于复杂的树,不能很好地概括数据。这就是所谓的过拟合。为了避免这个问题,必须设置剪枝、设置叶节点所需的最小样本数或设置树的最大深度等机制。
决策树可能是不稳定的,因为数据中的小变化可能导致生成完全不同的树。通过集成决策树来缓解这个问题。
学习最优决策树的问题在最优性的几个方面都是NP-complete的,甚至对于简单的概念也是如此。因此,实际的决策树学习算法是基于启发式算法,如贪婪算法,在每个节点上进行局部最优决策。这种算法不能保证返回全局最优决策树。这可以通过训练多棵树再集成一个学习器来缓解,其中特征和样本被随机抽取并替换。
有些概念很难学习,因为决策树不能很容易地表达它们,例如异或、奇偶校验或多路复用器问题。
如果某些类占主导地位,则决策树学习者会创建有偏见的树。因此,建议在拟合决策树之前平衡数据集。
适用场景
对于决策树分类而言,它更擅长分月亮型和半分型的数据,对于环状分布的数据效果并不是太好。
最擅长月亮型数据的是最近邻算法,RBF支持向量机和高斯过程
最擅长环形数据的是最近邻算法和高斯过程
最擅长半分的是朴素贝叶斯、神经网络和随机森林
本文选择经典的红酒数据集,也是sklearn自带的数据集。相比于鸢尾花数据集,它的特征会更多一些,对于参数调整前后的分数情况更加直观明显。
from sklearn import tree
import pandas as pd
from sklearn.datasets import load_wine #红酒数据集
from sklearn.model_selection import train_test_split
wine = load_wine()
print(wine.data)
print(wine.data.shape)
print(wine.target)
print(wine.feature_names)
print(wine.target_names)
df = pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1) #将特征和标签合并,axis=0为横向合并
print(df)
# 划分测试集和训练集
xtrain,xtest,ytrain,ytest = train_test_split(wine.data,wine.target,test_size=0.3)
# 创建决策树
clf = tree.DecisionTreeClassifier(criterion='entropy',random_state=42,splitter='random',max_depth=3,min_samples_leaf=10,min_samples_split=10) #实例化
#训练
clf = clf.fit(xtrain,ytrain)
#为测试集打分,分数每次运行会不一样,原因有两个:测试集和训练集划分不确定;决策树分类器的random_state参数影响
result = clf.score(xtest,ytest)
print('测试集打分',result)
print('训练集打分',clf.score(xtrain,ytrain))
#可视化
from sklearn.tree import export_graphviz
import pydot
import graphviz #需要自己导入 pip install graphviz
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
dot = tree.export_graphviz(clf
,feature_names=feature_name
,class_names=['琴酒','雪莉','贝尔摩德']
,filled=True #上色
,rounded=True) #圆角
graph = graphviz.Source(dot)
print(graph)
#重要性
importance = clf.feature_importances_
feature_importance = [(feature,importance.round(3)) for feature,importance in zip(feature_name,importance)]
#排序
feature_importance = sorted(feature_importance,key=lambda x :x[1],reverse=True)
#对应进行打印
[print('variable:{:20} importance: {}'.format(*pair)) for pair in feature_importance]
#绘制超参数曲线
import matplotlib.pyplot as plt
test = []
for i in range(100):
clf = tree.DecisionTreeClassifier(max_depth=2
# ,criterion='gini'
,criterion='entropy'
,random_state=i
,splitter='random')
clf.fit(xtrain,ytrain)
score = clf.score(xtest,ytest)
test.append(score)
plt.plot(range(100),test)
plt.xlabel('max_depth')
plt.ylabel('score')
plt.show()
总之,sklearn主要三步:建立模型评估对象,通过模型接口训练模型,最后通过模型接口提取需要的信息。其他模块内容会后续更新,我们一起学习~