文章目录
- 决策树
- ID3
- C4.5
- CART
- 代码
- 交叉验证
- 随机森林
- 袋装法bagging和提升法boosting
- 代码
决策树
决策树是一种监督学习方法,能从有特征和标签的数据中总结出决策规则,并用树状图来呈现这些规则,以此解决分类和回归问题。
决策树算法的两个核心问题
如何从数据表中找出最佳节点和最佳分支
如何让决策树停止生长,防止过拟合
构建决策树
原则上任意一个数据集上的所有特征都可以被拿来分枝,特征上的任意节点又可以自由组合,所以一个数据集上可以发展出非常多棵决策树;在这些树中分类效力最好的树叫全局最优树。
全局最优和局部最优
全局最优:整体来说分类效果最好的模型
局部最优:每一次分枝时都向着更好的分类效果分枝,但无法确认如此生成的树在全局上是否最优(贪心思想)
目前构建决策树算法主要包括ID3、C4.5、CART,区别在于划分依据。
不纯度
决策树的每个叶子节点中都会包含一组数据,在这组数据中,如果有某一类标签占有较大的比例,我们就说叶子节点“纯”,分枝分得好。
某一类标签占的比例越大,叶子就越纯,不纯度就越低,分枝就越好。
如果没有哪一类标签的比例很大,各类标签都相对平均,则说叶子节点”不纯”,分枝不好,不纯度高。
分类型决策树在叶子节点上的决策规则时少数服从多数
不纯度基于叶子节点来计算的,所以树中每个节点都会有一个不纯度;子节点的不纯度一定低于父节点,也就是说在同一棵决策树上叶子节点的不纯度一定是最低的。
不纯度的计算和表示因决策树模型而异,但都由误差率衍生而来。
决策树基本流程
from sklearn import tree
clf = tree.DecisionTreeClassifier() # 实例化
clf = clf.fit(X_train, y_train) # 用训练集训练模型
res = clf.score(X_test, y_test) # 导入测试集
误差率Classification errot(t)计算公式,t为节点,p(i|t)表示给定节点t中属于类别i的样本所占的比例。误差率越低,则纯度越高。
信息熵(香农熵),计算公式如下,其中c表示叶子节点上的标签类别的个数。
基尼(Gini)指数
主要用于CART决策树的纯度判定中,其计算公式如下
计算示例
三个指标随某个变量占比的变化曲线
决策树最终的优化目标是使得叶节点的总不纯度最低
ID3
ID3决策树在决定是否对某节点进行切分的时候,会尽可能选取使得该节点对应的子节点信息嫡最小的特征进行切分。
一个父节点下可能有多个子节点,每个子节点有自己的信息熵,所以父节点和其子节点的信息熵之差应该是父节点信息熵减去子节点信息熵的加权平均。
权重是使用单个叶子节点上所占的样本量除以父节点上的总样本量来确定的一个权重
父节点和子节点的不纯度下降数可由以下公式计算
决策树算法通常选择最大化增益的测试条件,最大化增益等价于最小化子结点的不纯性衡量的加权平均(父节点固定)。最后,当选择熵(entropy)作为公式的不纯性度量时,熵的差就是所谓信息增益(Information gain) Δinfo 。
ID3中的Information gain(信息增益)的计算方法就是用Entropy推导
决策树模型是一个典型的贪心模型,总目标是一个全局最优解,即一整套合理的分类规则使得最终叶节点的纯度最高,但全局最优解在随特征增加而呈现指数级增加的搜索空间内很难高效获取。
因此我们退而求其次,考虑采用局部最优来一步步推导结果—只要保证信息增益最大,我们就能得到次最优的模型。
ID3的局限性
ID3的局限主要源于局部最优条件,即信息增益的计算方法,主要有一下几点:
极限情况下取每个标签作为切分字段,每个分类的纯度都是100%,这样的分类方式没有效益。
不能直接处理连续型变量,需要先进行离散化。
没有剪枝的设置,容易过拟合。
C4.5
首先引入分枝度(IV:Information Value)的概念,来对信息增益的计算方法进行修正;即在信息增益计算方法的子节点总信息熵的计算方法中添加了随分类变量水平的惩罚项。
将信息熵计算公式中的p(i|t)(某类别样例占总样例数)改成p(vj)(某子节点的总样本数占父节点总样本数的比例);这其实就是加权求和时的权重。
IV计算公式
在C4.5中使用之前的信息增益除以分枝度作为选取切分字段的参考指标,该指标被称作Gain Ratio(获利比例,或增益率),计算公式如下
增益比例是决定对哪一列进行分枝的标准,分枝的是数字最大的那一列,本质是信息增益最大,分支度又较小的列(也就是纯度提升很快,但又不是靠着把类别分特别细来提升的那些特征)
在C4.5中还增加了针对连续变量的处理手段,对于连续性变量,使用以下步骤
对这一列数进行从小到大排序,选取相邻的两个数的中间数作为切分数据集的备选点,若一个连续变量有N个值,则在C4.5的处理过程中将产生N-1个备选切分点,并且每个切分点都代表着一种二叉树的切分方案。
CART
名称 | 分支方式 | 备注 |
ID3 | 信息增益 | ID3只能对离散属性的数据集构成决策树 |
C4.5 | 信息增益率 | 优化后解决了ID3分支过程中总喜欢偏向选择值较多的属性 |
CART | Gini系数 | 可以进行分类和回归,可以处理离散属性,也可以处理连续属性 |
代码
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
wine = load_wine()
import pandas as pd
pd.concat([pd.DataFrame(wine.data), pd.DataFrame(wine.target)], axis=1)
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data, wine.target, test_size=0.3)
Xtrain.shape
clf = tree.DecisionTreeClassifier(criterion="gini" # criterion="entropy"
,max_depth=4 # 最大深度
)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)# 返回预测的准确度accuracy
score
import graphviz
dot_data = tree.export_graphviz(clf, feature_names=wine.feature_names, class_names=wine.target_names)
graph = graphviz.Source(dot_data)
graph
[*zip(wine.feature_names, clf.feature_importances_)]# 权重
import matplotlib.pyplot as plt
test = []
for i in range(10):
clf = tree.DecisionTreeClassifier(criterion="entropy", splitter="random", max_depth=i+1)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
test.append(score)
plt.plot(range(1, 11), test)
plt.show()
参考链接
https://www.bilibili.com/video/BV1BE411c7jB
交叉验证
交叉验证是用来观察模型的稳定性的一种方法,我们将数据划分为n份,依次使用其中一份作为测试集,其他n-1份作为训练集,多次计算模型的精确性来评估模型的平均准确程度。
随机森林
袋装法bagging和提升法boosting
袋装法(bagging) 的核心思想是构建的多个相互独立的评估器,然后对其预测进行平均或多数表决原则来决定继承评估器的结果。bagging的代表模型就是随机森林。
提升法(boosting) 中的评估器按顺序一一构建。结合弱评估器的力量一次次对难以估计的样本进行预测,从而构成一个强评估器。
随机森林是非常具有代表性的Bagging集成算法,它的所有基评估器都是决策树,分类树组成的森林就叫做随机森林分类器,回归树所集成的森林就叫做随机森林回归器。
单个决策树的准确率越高,随机森林的准确率也会越高,因为装袋法是依赖于平均值或者少数服从多数原则来决定集成的结果的。
sklearn参数n_estimators
sklearn参数n_estimators是森林中树的个数,即基评估器的数量,这个参数越大,往往效果越好。但是达到一定程度后,精确率往往上升缓慢或者波动,并且占用内存和计算量也变大。
sklearn参数bootstrap
要让基分类器尽量都不一样,一种很容易理解的方法是使用不同的训练集来进行训练,而袋装法bagging正是通过有放回的随机抽样技术来形成不同的训练数据,bootstrap就是用来控制抽样技术的参数。bootstrap参数默认为True,代表有放回的随机抽样。
sklearn参数oob_score
当然,这也不是绝对的,当n和n_estimators都不够大的时候,很可能就没有数据掉落在袋外,自然也就无法使用oob 数据来测试模型了。
如果希望用袋外数据来测试,则需要在实例化时就将oob_score这个参数调整为True,
sklearn参数random_state 相当于随机数种子
sklearn属性oob_score_
oob_score_来查看我们的在袋外数据上测试的结果
sklearn属性estimators_
森林中树的情况
代码
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_wine
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
wine = load_wine()
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data, wine.target, test_size=0.25)
clf = DecisionTreeClassifier(random_state=1)
clf=clf.fit(Xtrain, Ytrain)
score_c = clf.score(Xtest, Ytest)
rfc = RandomForestClassifier(random_state=1)
rfc = rfc.fit(Xtrain, Ytrain)
score_r = rfc.score(Xtest, Ytest)
print(score_c)
print(score_r)
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
rfc = RandomForestClassifier(n_estimators=25)
rfc_s = cross_val_score(rfc, wine.data, wine.target, cv=10)
clf = DecisionTreeClassifier()
clf_s = cross_val_score(clf, wine.data, wine.target, cv=10)
plt.plot(range(1, 11), rfc_s, label="RandomForest")
plt.plot(range(1, 11), clf_s, label="DecisionTree")
plt.legend()
plt.show()
rfc_l = []
clf_l = []
for i in range(10):
rfc = RandomForestClassifier(n_estimators=25)
rfc_s = cross_val_score(rfc, wine.data, wine.target, cv=10).mean()
rfc_l.append(rfc_s)
clf = DecisionTreeClassifier()
clf_s = cross_val_score(clf, wine.data, wine.target, cv=10).mean()
clf_l.append(clf_s)
plt.plot(range(1, 11), rfc_l, label="RandomForest")
plt.plot(range(1, 11), clf_l, label="DecisionTree")
plt.legend()
plt.show()
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_wine
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
wine = load_wine()
rfc = RandomForestClassifier(random_state=1, oob_score=True)
rfc = rfc.fit(wine.data, wine.target)
rfc.oob_score_
参考链接
https://www.bilibili.com/video/BV1z7411C77s