决策树
什么是决策树
决策树其实就是一个树形结构,而由于其结构为树,所以决策树能对样本进行分析,因为一个树形结构其实就相当于if-else结构, 树的每一层可以看做是对一个特征的决策。比如下面这个决策是否打篮球的例子,先根据年龄特征:如果年龄小于15则有可能,而大于15则没有可能,然后再根据性别:如果是男性则有可能,是女性则不可能。所以通过一系列的决策便能得到一个数据的类别。
决策树创建过程 (如果不想看数学,可直接跳过看下面应用)
在我们使用决策树进行预测的时候,前提是我们有了一棵决策树,所以决策树的关键点在于怎么建造树,建造树的过程里面涉及几个数学概念,下面依次展开。
关于熵的概念
熵以前可能我们都接触过,熵代表了混乱程度,比如两个集合,集合一为:{1,1,1,1,2,2},集合二为:{1,2,3,4,5,6},很显然集合一的混乱程度要低一点,集合二的混乱程度要高一点,但是这个只是我们直观的感觉,现在要把这个直观的感觉转换成数学语言,使用数学公式来表达熵,那么熵可以表示为:
H
(
x
)
=
−
∑
p
(
i
)
∗
l
o
g
p
(
i
)
,
i
=
1
,
2
,
3
,
…
,
n
H(x) = -\sum p(i) * log{p(i)} ,i = 1,2,3,\dots , n
H(x)=−∑p(i)∗logp(i),i=1,2,3,…,n
对于这个公式可以用一个极端例子来表示,比如一个集合全部都是1,那么其概率p = 1,所以计算的熵值为0,也就是代表熵值很小,所以混乱程度也很小。所以这个 H ( x ) H(x) H(x)可以作为衡量一组数据的混乱程度。
树的构造
有了熵的概念我们就可以构造树了,其实树的构造主要是选择哪个作为根节点,当选择完根节点后,其左右子树同样也是选择计算子树的根节点(这就是一个同样的过程),所以这里介绍怎么找到根节点。
在进行树的构造,我们的目的是构造一棵尽量矮的树,并且能赶快把数据分开,也就是赶快分到叶子节点,而叶子节点的特点就是种类比较少,纯度比较高,所以也就是熵值比较低的节点,所以你的目的就是找到一个根节点,划分后,其熵值下降的最快,这个熵值下降的值就叫做信息增益。比如下面这个例子:
里面有14个样本,表示不同因素对于是否出去玩的影响,outlook代表外面天气…。
选择根节点步骤:
一、先计算目前的熵值,在14个样本中有9天是出去玩,5天不出玩,所以熵值为 −(9/14*log(9/14)+5/14*log(5/14))=0.940。
二、然后我们在计算基于outlook进行划分后的熵值。
1. 当outlook = sunny时,可以看出共有5个样本其中2个出去玩,3个不出去玩,所以对应熵值为0.971。
2. 当outlook = overcast时,可以看出共有4个样本其中4个出去玩,所以对应熵值为0。
3. 当outlook = rainy时,可以看出共有5个样本其中3个出去玩,2个不出去玩,所以对应熵值为0.971(可以看出如果总样本个数一样,然后分布一样其熵值也一样)。
4. 而outlook取值为sunny,overcast,rainy的概率分别为:5/14, 4/14, 5/14,所以使用outlook进行划分的最终熵值是 5/14 * 0.971 + 4/14 * 0 + 5/14 * 0.971 = 0.693
三、根据原来的熵值0.940,以及现在根据outlook划分后的熵值0.693,得出其信息增益为0.940-0.693 = 0.247。
四、使用上面同样的方法(第二步开始)计算基于temperature、humidity、windy划分得到的信息增益,然后比较得出最大的信息增益那个,这样就可以使这个树向着变纯的方向变化的更快,树也会更矮。
然后第二层也同样计算熵,然后按照特征进行划分,计算信息增益,最后分别得到子树的根节点,最后组成一棵树。
当前构造方法的弊端
假如当前特征值里面有一个ID特征,那么显然每个样本ID是惟一的,所以此时对树的根节点划分的时候会出现ID的信息增益是最大的(因为基于ID划分的熵值为0),但这样是没有意义的,因为ID不具有实际意义。这个时候就可以引入其他的方式来代替信息增益的计算方式,比如C4.5、GINI系数等,有兴趣可以查阅资料了解,这些方法的不同之处仅仅在与在算下降的时候换了中方式,原来我们是使用熵值以及熵值的差来作为评判标准的,而其他算法则使用不同评判标准。
使用sklearn中的决策树
导入相应的库
from sklearn.tree import DecisionTreeClassifier
from sklearn import datasets,model_selection
import numpy as np
import matplotlib.pyplot as plt
datasets里面存储了一些数据集可以直接使用,model_selection进行测试集和训练集的划分,你也可以使用交叉验证进行划分。
读数据集
#读数据集
iris = datasets.load_iris()
X = iris.data
y = iris.target
#数据集划分
X_train,X_test,y_train,y_test = modeel_data = model_selection.train_test_split(X, y,test_size=0.25,random_state=0,stratify=y)
这段代码实现了读取数据集,并且把数据集划分成训练集和测试集两部分。
对数据集进行训练并进行预测
# 初始化一个决策树,其中criterion代表采用的策略,这里使用gini,你也可以选择熵值entropy策略。max_depth是指生成树的最大高度,这样可以避免树太过于高,造成过拟合
clf = DecisionTreeClassifier(criterion="gini",max_depth=10)
# 开始训练
clf.fit(X_train,y_train)
# 准确率预测
score= clf.score(X_test,y_test)
通过画图分析结果
这次是画出来不同策略在不同深度下对最终正确率的影响。
# 生成树的时候可以采用gini(CART决策树)也可以使用信息熵entropy(ID3)策略
# entropy gini
criterions = ['gini','entropy']
# 深度从1到40 每次都测试一下
depths = np.arange(1,40)
# 记录不同策略下的分数,train代表用该树验证训练集的正确率(一般都很高的)
scores ={criterions[0]:[],criterions[1]:[],"train":[]}
# 先验证两种不同策略下的不同高度的准确率
for criterion in criterions:
for depth in depths:
clf = DecisionTreeClassifier(criterion=criterion,max_depth=depth)
clf.fit(X_train,y_train)
scores[criterion].append(clf.score(X_test,y_test))
# 再验证一下该树在训练集下的正确率(作为参考,一把这个正确率能达到100%),可以最为gini和entropy的参考
for depth in depths:
clf = DecisionTreeClassifier(criterion=criterion,max_depth=depth)
clf.fit(X_train,y_train)
scores["train"].append(clf.score(X_train,y_train))
# 画第一个折线图,在策略为gini时不同高度的情况
plt.plot(depths,scores[criterions[0]],marker='o',label =criterions[0])
# 画第二个折线图,在策略为entropy时不同高度的情况
plt.plot(depths,scores[criterions[1]],marker='*',label =criterions[1])
# 画第三个折线图,在训练集时不同高度的情况
plt.plot(depths,scores["train"],marker='*',label ="best")
plt.legend(framealpha=0.5,loc='best')
plt.show()
最终图片如下:
结论
可以看出一般情况下在训练集下其准确率几乎100%,然后gini通常由于entropy,但是树的高度并不是越高越好,如果越高可能会出现过拟合现象。
欢迎大家关注我的微信公众号,未来上面会推送python
机器学习
算法学习
深度学习
论文阅读
以及偶尔的小鸡汤
等内容。ようこそいらっしゃい!
搜索 coderwangson 关注