文章目录
一、 随机森林
1. 引入随机森林算法
一棵决策树可以学到很复杂的规则。然而,很可能会导致过拟合问题——学到的规则只适用于训练集。解决方法之一就是调整决策树算法,限制它所学到的规则的数量。例如,把决策树的深度限制在三层,只让它学习从全局角度拆分数据集的最佳规则,不让它学习适用面很窄的特定规则,这些规则会将数据集进一步拆分为更加细致的群组。使用这种折中方案得到的决策树泛化能力强,但整体表现稍弱。
为了弥补上述方法的不足,我们可以创建多棵决策树,用它们分别进行预测,再根据少数服从多数的原则从多个预测结果中选择最终预测结果。这正是随机森林的工作原理。
2. 为什么随机森林的准确率要高于单棵决策树?
随机森林的本质是一种装袋集成算法(bagging),装袋集成算法是对基评估器的预测结果进行平均或用多数表决原则来决定集成评估器的结果。
假设我们建立一个包含25棵树的随机森林算法。对任何一个样本而言,平均或多数表决原则下,当且仅当有13棵以上的树判断错误的时候,随机森林才会判断错误。我们假设一颗树判断错误的可能性为0.2(ε),那13棵树以上都判断错误的可能性为:
e
r
f
c
=
∑
i
=
13
25
C
25
i
ε
i
(
1
−
ε
)
25
−
i
e_{rfc} = \sum_{i=13}^{25} C_{25}^iε^i(1-ε)^{25-i}
erfc=i=13∑25C25iεi(1−ε)25−i
其中,i是判断错误的次数,也就是判断错误的树的数量,ε是一棵树判断错误的概率,(1-ε)是判断正确的概率,一共判断正确(25-i)次。
我们使用代码计算一下:
[1]:import numpy as np
from scipy.special import comb
np.array([comb(25,i)*(0.2**i)*((1-0.2)**(25-i)) for i in range(13,26)]).sum()
可见,判断错误的几率为0.00036904803455582827,可见几率是远比一棵树判断错误的概率0.2小得多的。
3. 袋装法(bagging)
上述过程有两个问题:
一是我们使用随机森林创建的多颗决策树在很大程度上是相同的——每次使用相同的训练集和测试集,每次使用的类都是DecisionTreeClassifier,每次都是一样的参数,那么按道理来说,创建的多颗决策树应该都是相同的.这就意味着随机森林中的所有树模型判断结果都一样,要么都对,要么都错。那么随机森林无论应用何种集成原则来求结果,都无法超过单棵决策树才对。解决方法就是每次随机从数据集中选取一部分数据用作训练集,这样每棵树使用不同的训练集进行训练,生成的分类决策树也就不同,也就是袋装法。
Bagging采用的是有放回的随机抽样技术来形成每次不同的训练集。在一个含有m个样本的原始训练集中,我们进行随机采样,每次采样一个样本,并在抽取下一个样本之前将该样本放回原始训练集,也就是说下次采样时这个样本依然可能被采集到,这样采集m次,最终得到一个和原始训练集一样大的,m个样本组成的自助集。由于是随机采样,这样每次的自助集和原始数据集不同,和其他的采样集也是不同的。这样我们就可以自由创造取之不尽用之不竭,并且互不相同的自助集,用这些自助集来训练我们的决策树,我们的决策树自然也就各不相同了。
第二个问题是用于前几个决策节点的特征非常突出。即使我们随机选取部分数据用作训练集,创建的决策树相似性仍旧很大。
解决方法是,随机选取部分特征作为决策依据。在分类决策树中,决策树从最重要的特征中随机选择出一个特征来进行分枝,因此每次生成的决策树都不一样,这个功能由参数random_state控制。随机森林中其实也有random_state,用法和分类树中相似,只不过在分类树中,一个random_state只控制生成一棵树,而随机森林中的random_state控制的是生成森林的模式。具体信息我将会在参数讲解部分说明。
然后,使用随机从数据集中选取的数据和(几乎是)随机选取的特征,创建多棵决策树。这就是随机森林,虽然看上去不是那么直观,但这种算法在很多数据集上效果很好。
二、sklearn中的随机森林实现
1. 参数
class sklearn.ensemble.RandomForestClassifier(
n_estimators=100,
criterion='gini',
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features='auto',
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
bootstrap=True,
oob_score=False,
n_jobs=None,
random_state=None,
verbose=0,
warm_start=False,
class_weight=None,
ccp_alpha=0.0,
max_samples=None
)
由于随机森林的基评估器都是决策树,所以很多参数都与决策树相同。因此这里只对n_estimators,bootstrap,oob_score,random_state,verbose这几个参数进行讲解。
1. 1 n_estimators
这是森林中决策树的数量。这个参数对随机森林模型的精确性影响是单调的,n_estimators越大,模型的效果往往越好。但是相应的,任何模型都有决策边界,n_estimators达到一定的程度之后,随机森林的精确性往往不在上升或开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越长。在scikit-learn 0.22.2版本中,默认n_estimators数量为100,也就是默认会创建100棵树。
我们先来使用红酒数据集创建一个随机森林模型:
引包
[1]:import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split,cross_val_score
导入红酒数据集
[2]:wine = load_wine()
切分训练集和测试集
[3]:Xtrain,Xtest,Ytrain,Ytest = train_test_split(wine.data,wine.target,test_size = 0.3)
建立决策树模型和随机森林模型并进行对比
[4]:clf = DecisionTreeClassifier(random_state=0)
clf = clf.fit(Xtrain,Ytrain)
score_c = clf.score(Xtest,Ytest)
rfc = RandomForestClassifier(random_state=0)
rfc.fit(Xtrain,Ytrain)
score_r = rfc.score(Xtest,Ytest)
[5]:score_c # 分类决策树
0.9259259259259259
[6]:score_r # 分类随机森林
0.9444444444444444
这样我们就能很明显的看出,随机森林算法的准确率确实要高于单棵决策树算法。
1.2 random_state
在分类树中,一个random_state只控制生成一棵树,而随机森林中的random_state控制的是生成森林的模式。
这里我们使用代码来实际测试一下:
[7]:rfc = RandomForestClassifier(n_estimators=25,random_state=2)
rfc = rfc.fit(Xtrain,Ytrain)
[8]:for i in range(len(rfc.estimators_)):
print(rfc.estimators_[i].random_state)
511939657
1686894515
93846488
886864977
379779686
279069780
2088470653
1662082349
1866838260
1324060400
1570863295
1323564635
1775659522
564993231
902010222
350630086
1398165819
455259697
55451085
1024089206
891714713
1124267110
1637979666
907680114
35432939
如果我们多运行几次,我们可以看到,当我们固定random_state时,随机森林中生成是一组固定的树,但每棵树依然是不一致的。
1.3 bootstrap和oob_score
bootstrap默认为True,代表采用bagging有放回的随机抽样技术。通常,这个参数不会被我们设置为False.
然而有放回抽样也会有自己的问题。由于是有放回,一些样本可能在同一个自助集中出现多次,而其他一些却可能
被忽略,一般来说,自助集大约平均会包含63%的原始数据。因为每一个样本被抽到某个自助集中的概率为:
1
−
(
1
−
1
/
n
)
n
1-(1-1/n)^n
1−(1−1/n)n
当n足够大时,这个概率收敛于1-(1/e),约等于0.632。因此,会有约37%的训练数据被浪费掉,没有参与建模,这些数据被称为袋外数据(out of bag data ,简写为oob)。除了我们最开始就划分好的测试集外,这些数据也可以被用来作为集成算法的测试集。也就是说,在使用随机森林的时候,我们可以不划分测试集和训练集,只需要用袋外数据来测试我们的模型即可。但是当数据集本身不够大或者树的个数n_estimators不够大时,很可能袋外数据就很少,这时候不能使用袋外数据作为测试集。
如果需要使用袋外数据来测试,则需要在模型实例化的时候就将oob_score这个参数调整为True,训练完毕后,我们可以用随机森林的另一个重要属性:oob_score_ 来查看我们使用袋外数据作为测试集的训练结果。
[9]:rfc = RandomForestClassifier(n_estimators=25,random_state=2,oob_score=True)
rfc = rfc.fit(wine.data,wine.target)
rfc.oob_score_
0.9662921348314607
2. 画图
2.1 一组交叉验证下决策树与随机森林的效果对比
交叉验证:是数据集划分为n份,依次取每一份做测试集,每n-1份做训练集,多次训练模型以观测模型稳定性的方法
rfc = RandomForestClassifier(random_state=0)
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()
可以看出单个决策树的波动轨迹是和随机森林一致的。决策树的准确率提高,则随机森林的准确率也随之升高。
2.2 n_estimators的学习曲线
rfc_l = []
for i in range(200):
rfc = RandomForestClassifier(n_estimators=i+1)
rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
rfc_l.append(rfc_s)
print(max(rfc_l),rfc_l.index(max(rfc_l))) # 输出得分最高
plt.plot(range(1,201),rfc_l)
plt.show()
可以看出对于红酒数据集来说,当n_estimators=45是,得分最高。准确率在98.9%