9.2 随机森林#

9.2.1 随机森林原理#

正如在9.1.3节中所介绍的那样,随机森林本质上是基于决策树的Bagging集成学习模型,因此,随机森林的建模过程总体上可以分为3步[3]:

第1步,对原始数据集进行随机采样,得到多个训练子集。

第2步,在各个训练子集上训练得到不同的决策树模型。

第3步,将训练得到的多个决策树模型进行组合,然后得到最后的输出结果。

如图9-2所示为随机对样本点和特征采样后训练得到的若干决策树模型组成的随机森林。从图9-2中可以看出,即使同一个样本在不同树中所归属的叶子节点也不尽相同,甚至连类别也可能不同,但是这也充分体现了Bagging集成模型的优点,通过“平均”来提高模型的泛化能力。

图 9-2 随机森林原理示意图

在图9-2中,多个不同结构的决策树模型构成了随机森林,并且在模型输出时将会以投票的方式决策出最终的输出类别。同时,随机森林与普通Bagging集成学习方法存在的一点差别就是,随机森林中每棵决策树在每次划分节点的过程中,还会有一个随机的过程,即只会从已有的特征中再随机选择部分特征取值参与节点划分,这一过程被称为Feature Bagging。之所以要这么做,是为了减小各个树模型之间的关联性。例如训练数据中如果存在着某些差异性较大的特征取值,则所有的决策树在节点划分时就会选择同样的特征,使最终得到的决策树之间具有较强的关联性,即每棵树都类似。

9.2.2 随机森林示例代码#

介绍完随机森林的基本原理后再来看一看如何通过sklearn完成随机森林的建模任务。在sklearn中,可以通过语句from sklearn.ensemble import RandomForestClassifier导入模块随机森林。下面先来介绍一下RandomForestClassifier类中常见的几个重要参数及其含义,示例代码如下:

1 def __init__(self, n_estimators=100, criterion="gini",
2     max_depth=None, min_samples_split=2, min_samples_leaf=1,
3     max_features="auto", bootstrap=True, max_samples=None):

在上述代码中,第1行n_estimators表示在随机森林中决策树的数量; criterion用于指定构建决策树的算法,可参见第8章内容。第2行 max_depth表示允许决策树的最大深度; min_samples_split表示节点允许继续划分的最少样本数,即如果划分后的节点中样本数少于该值,将不会进行划分; min_samples_leaf表示叶子节点所需要的最少样本数; max_features表示每次对节点进行划分时所选特征的最大数量,即节点每次在进行划分时会先在原始特征中随机选取max_features个候选特征,然后在候选特征中选择最佳特征; bootstrap表示是否对原始数据集进行采样,如果其值为False,则所有决策树在构造时均使用相同的样本; max_samples表示每个训练子集中样本数量的最大值(当bootstrap=True时),其默认值为None,即等于原始样本的数量。

注意:max_samples=None仅仅表示采样的样本数等于原始训练集的样本数,不代表抽样后的子训练集等同于原始训练集,因为采样时样本可以重复。

一般来讲,在sklearn的各个模型中,对于大多数参数来讲保持默认即可,对于少部分关键参数可采样交叉验证进行选择。下面以iris数据集为例进行RandomForestClassifier的集成学习建模任务,完整代码可参见 AllBooKCode/Chapter09/C04_ensemble_random_forest.py 文件,示例代码如下:

1 if __name__ == '__main__':
2     x_train, x_test, y_train, y_test = load_data()
3     model = RandomForestClassifier(n_estimators=2, max_features=3)
4     model.fit(x_train, y_train)
5     print(model.score(x_test, y_test)) # 0.95

上述代码便是利用随机森林来进行分类任务的完整建模过程。可以看到,尽管随机森林这么复杂的一个模型,在sklearn中同样可以通过几行代码来完成。同时,在完成随机森林的训练后,可以通过model.estimators属性来得到所有的决策树对象,然后分别对其进行可视化就可以得到整个随机森林可视化结果。当然,最重要的是可以通过model.feature_importances属性来得到每个特征的重要性程度以进行特征筛选,以便去掉无关特征。

9.2.3 特征重要性评估#

从决策树的构造原理便可以看出,越是靠近决策树顶端的特征维度越能对不同类别的样本进行区分,这就意味着越是接近于根节点的特征维度越重要,因此,在sklearn中的类DecisionTreeClassifier里面,同样也有feature_importances_这一类属性,以便输出每个特征的重要性值。只是通过随机森林进行特征重要性评估更加准确,因此才将这部分内容放到了这里。不过想要弄清楚随机森林中的特征重要性评估过程,还得从决策树说起。

1. 决策树中的特征评估

在sklearn中,决策树通过基于基尼不纯度的减少量来对特征进行重要性评估,当然基尼不纯度也可以换成信息增益或者信息增益比。具体地,对于决策树中划分每个节点的特征来讲,其特征重要性计算公式为[1]

$$ \text{importance}=\frac{N_t}{N}*(\text{impurity}-\frac{N_{tL}}{N_t}*\text{left\_impurity}-\frac{N_{tR}}{N_t}*\text{right\_impurity})\tag{9-2} $$

其中,$N$表的样本数; $N_t$表示当前节点的样本数;$\text{ impurity}$表示当前节点的不纯度; $N_{tL}$表示当前节点左孩子中的样本数; $\text{left\_impurity}$表示当前节点左孩子的不纯度; $N_{tR}$表示当前节点右孩子中的样本数;$\text{right\_impurity}$表示当前节点右孩子的不纯度。 以9.2.2节随机森林里的其中一棵决策树为例,其在每次进行节点划分时的各项信息如图9-3所示。

图 9-3 决策树特征重要性评估

这里有一个细节需要注意,在图9-3中每个节点里samples的数量指的是不重复的样本数(因为采样会有重复),而列表value中的值则包含重复样本。例如在根节点中,samples=62表示一共有62个不同的样本点,但实际上该节点中有105个样本点,即有43个样本点为重复出现的样本点。

此时,对于特征petal width来讲,根据式(9-2)其特征重要性值为

$$ \frac{105}{105}\times \left( 0.657-\frac{70}{105}\times 0.507-\frac{35}{105}\times 0 \right)\approx 0.319\tag{9-3} $$

对于特征petal length来讲,由于其在两次节点划分中均有参与,所以它的特征重要性为

$$ \frac{70}{105}\times \left( 0.507-\frac{27}{70}\times 0-\frac{43}{70}\times 0.089 \right)+\frac{43}{105}\times \left( 0.089-0 \right)\approx 0.338\tag{9-4} $$

对于另外两个特征sepal length和sepal width来讲,由于两者并没有参与决策树节点的划分,所以其重要性均为0。

2. 随机森林中的特征评估

在介绍完决策树中的特征重要性评估后,再来看随机森林中的特征重要性评估过程就相对容易了。在sklearn中,随机森林的特征重要性评估主要是基于多棵决策树的特征重要性结果计算而来,称为平均不纯度减少量(Mean Decrease in Impurity,MDI)。MDI的主要计算过程就是将多棵决策树的特征重要性值取一次平均值。

对于9.2.2节中的随机森林来讲,其另外一棵决策树在每次进行节点划分时的各项信息如图9-4所示。

图 9-4 随机森林特征重要性评估

从图9-4可以看出,此处一共有2个特征参与了节点的划分。根据式(9-2)可知,特征petal length的重要性为

$$ \frac{105}{105}\times \left( 0.656-\frac{66}{105}\times 0.478 \right)+\frac{66}{105}\times \left( 0.478-\frac{44}{66}\times 0.165 \right)+\frac{7}{105}\times 0.49\approx 0.619\tag{9-5} $$

特征petal width的重要性为

$$ \frac{44}{105}\times \left( 0.165-\frac{7}{44}\times 0.49 \right)\approx 0.036\tag{9-6} $$

到此为止,对于第9.2.2节中的随机森林,其两棵决策树对应的计算所得到特征重要性(未标准化)如表9-2所示。

表 9-2 决策树特征重要性表

在sklearn中,对于决策树计算得到的特征重要性值默认情况下还会进行标准化,即每个维度均会除以所有维度的和。进一步,对于随机森林来讲,其各个特征的重要性值则为所有决策树对应特征重要性的平均值,因此,对于表9-2中的结果来讲最终每个特征重要性值为0、0、0.729和0.271。关于上述详细的计算过程可以参见 AllBooKCode/Chapter09/C05_ensemble_random_forest_features.py文件。

从最后的结果可以看出,在数据集iris中对分类起决定性作用的是最后两个特征维度,因此,各位读者也可以进行一个对比,只用最后两个维度进行分类并观察其准确率。完整示例代码可参见 AllBooKCode/Chapter09/C06_feature_importance_comp.py文件。

9.2.4 小结#

在本节中,我们首先介绍了随机森林的基本原理,然后介绍了sklearn中随机森林模块RandomForestClassifier的基本用法及其中常见参数的作用,最后详细介绍了如何通过随机森林来对特征进行重要性评估,包括具体的计算及示例代码等。在下一节内容中,我们将介绍一个实际的基于随机森林的分类任务。