【scikit-learn文档解析】集成方法 Ensemble Methods(上):Bagging与随机森林

【scikit-learn文档解析】集成方法 Ensemble Methods(上):Bagging与随机森林

(题图:Piet Mondrian - Arbre

系列链接:

【scikit-learn文档解析】集成方法 Ensemble Methods(上):Bagging与随机森林 - 知乎专栏

【scikit-learn文档解析】集成方法 Ensemble Methods(下):AdaBoost,GBDT与Voting - 知乎专栏


在机器学习中,集成方法(ensemble learning)把许多个体预测器(base estimator)组合起来,从而提高整体模型的鲁棒性泛化能力

集成方法有两大类:

  • Averaging独立建造多个个体模型,再取它们各自预测值的平均,作为集成模型的最终预测;能够降低variance。例子:随机森林,bagging。
  • Boosting顺序建立一系列弱模型,每一个弱模型都努力降低bias,从而得到一个强模型。例子:AdaBoost,Gradient Boosting。


1. Bagging

Bagging全称bootstrap aggregating。这种方法,把个体预测器当做黑盒子处理,不进行进一步修改,所以,它的个体预测器可以是任何机器学习算法。它对训练数据集进行随机取样,并使用取样后的数据子集,训练每一个个体预测器。在预测时,每一个预测器都会做出预测,整体结果则是每个预测的平均。

Bagging能降低模型的variance,所以它可以对抗过拟合。一般而言,bagging需要使用variance高、比较复杂的强个体模型。具体到常用的决策树上,就体现在单个决策树的层数更深。(相比之下,boosting需要使用bias高、比较简单的弱个体模型。)


根据数据子集(用于训练每一个个体分类器)建立方式的不同,bagging有4个种类:

  • Pasting:针对样本,取所有样本的随机子集。[3]
  • Bagging:针对样本,进行重置随机抽样(sample with replacement),可能会有重复样本。[4]
  • Random Subspaces:针对特征,取所有特征的随机子集。[5]
  • Random Patches:针对特征和样本,取所有特征和所有样本的随机子集(组合了Pasting和Random Subspaces)[6]

scikit-learn代码实现的bagging算法,可以包括以上所有的情形。



1.1. 代码实现

scikit-learn提供了BaggingClassifier和BaggingRegressor两种方法:

参数解析:

  • base_estimator:个体预测器,需要是一个scikit-learn的分类器或回归器。如果没有给出,那么默认使用决策树(不推荐,不如RandomForest)。
  • n_estimators:个体预测器的数量。通常,预测器越多,整体模型的variance越低。
  • max_samples:每个数据子集(用于训练个体预测器)的样本数量。可以是浮点数(0.0至1.0,表示取样本占所有样本的比例),也可以是整数(表示样本的实际数量)。注意:如果输入了1而不是1.0,那么每个数据子集仅包含1个样本,会导致严重失误。
  • max_features:每个数据子集的特征数量。数值原理同上。
  • bootstrap:在随机选取样本时是否进行重置(sample with replacement)。
  • bootstrap_features:在随机选取特征时是否进行重置。
  • oob_score:是否计算out-of-bag分数。每个个体预测器,都只在原始数据集的一部分上训练。所以,可以用它在剩下样本上的误差(out-of-bag error),来估计它的泛化误差(generalization error)。
  • warm_start:如果是True,那么在下一次使用fit方法时,向原有的模型再增加n_estimators个新的个体预测器,不丢弃原有的个体预测器。
  • n_jobs:并行计算的进程数量,如果是-1则使用全部CPU核。
  • random_state:随机状态,用于得出可复现的结果。
  • verbose:控制屏幕上进程记录的冗长程度。


1.2. 例子

from sklearn.ensemble import BaggingClassifier
sklearn.neighbors import KNeighborsClassifier
bagging = BaggingClassifier(KNeighborsClassifier(), n_estimators=10,
                            max_samples=0.5, max_features=0.5)

如此一来,我们得到了一个由10个KNNClassifier组成的集成分类器。



1.3. 比较Bagging和个体模型的bias与variance [7]

在机器学习中,误差(error)可以被分解为biasvariancenoise三个部分。

对于任何一个有监督学习问题(目标是求出P(y|x)),最好的模型,无疑是一个完全知道数据概率分布的先知oracle或Bayes model)。然而,因为数据本身存在一定误差,所以先知也会产生一定误差,这个误差被称为noiseBayes error,是所有可能情形中最低的误差。bias是某个模型平均error与Bayes error的差距,而variance则反映了模型在同一问题的不同版本上预测的差异大小。



如上图所示,在noise不变的情况下,单个决策树和bagging(决策树)的bias都很低,但是bagging能够显著降低模型的variance。



2. 随机森林(random forest)

为了增加个体预测器的多样性,随机森林在bagging(决策树)的基础上更进一步,在每棵树的建造过程中增加了随机性。在每棵随机树的生长过程中,节点分裂时,所用的特征不再是所有特征中最好的,而是特征的一个子集中最好的。这种随机性降低了运算量,略微提升了bias,极大提升了决策树的多样性,在取平均数之后可以大幅减小variance。整体而言,随机森林是一个非常强大的算法。

随机森林有若干个变体,包括extremely randomized trees(简称ExtraTrees,暂未找到中文翻译,欢迎补充)。在随机森林的基础上,ExtraTrees在每次节点分裂的阈值(threshold for splitting)上加入了随机性。对于任意单个特征,ExtraTrees随机选取一些阈值,并在其中选取最好的阈值作为分类点。和随机森林相比,ExtraTrees的variance更低,bias更高。

在Iris数据集上的运行结果,从左到右分别是:单个决策树、随机森林、ExtraTrees、AdaBoost。由图片可见,单棵决策树预测的自信度最高,但容易过拟合;ExtraTrees预测的自信度略低于随机森林,但它的决策边界也更为平滑。[8]

曾经,随机森林相比Gradient Boosting的一大优势就是能够并行计算,因为不同决策树的建造是相互独立的。然而,LightGBM和XGBoost通过不同特征之间的并行实现了gbdt的分布式计算。所以如今,这个优势已经没有那么明显了。



2.1. 代码实现

scikit-learn文档链接:

参数解析(上文已经包括了一些参数的解释,在此不再重复):

  • n_estimators
  • criterion:每棵树分裂节点时的标准,针对分类器的有gini(基尼指数)和entropy(信息熵),针对回归器的有mse(均方差,mean squared error)和mae(mean absolute error,中文未知,欢迎补充)
  • max_depth:每棵树最大的深度,(和boosting相比)一般都比较深。增大此参数可以增加模型variance。
  • min_samples_split:节点分裂时的最小样本数量。增大此参数可对抗过拟合。
  • min_samples_leaf:每个叶上最小的样本数量。增大此参数可对抗过拟合。
  • min_weight_fraction_leaf:每个叶上最小的样本权重比例(在fit时不使用sample_weight时,每个样本权重相同,这时权重比例的计算方法是:叶子上样本数量/总样本数)。增大此参数可对抗过拟合。
  • max_features:和普通的bagging相比,增加了auto、sqrt和log2的选项。
  • max_leaf_nodes:每棵树叶子数量的限制。
  • min_impurity_split:节点继续分裂时的impurity阈值。如果impurity低于这个参数,那么该决策树在这个节点上将停止生长,这个节点将成为一个叶子。impurity的计算方式取决于上文的criterion参数。
  • bootstrap
  • oob_score
  • n_jobs
  • random_state
  • verbose
  • warm_start
  • class_weight:仅用于分类器。可以不输入,也可以输入字符串balanced或balanced_subsample,也可以输入dict(格式为{class_label: weight})。这个参数通常用于调节样本不平衡的状况。


2.2. 用随机森林评估特征的重要性

一个特征在决策树上的深度,可以反映它对预测的影响力,也就是它的重要性。如果一个特征被用于最顶层的节点分裂,那么它的数值影响了所有的样本,说明它对预测任务非常重要。相比之下,用于最底层节点分裂的特征,只影响了一两个样本,对最终预测的贡献不大。

在随机森林中,我们可以取所有随机树的特征重要性的平均值,得到模型整体的特征重要性。这一数据可以被用于特征选择和特征提取。它的一大优点是,特征重要性的计算是在模型训练的过程中自动完成的,不需要额外的计算量(在思路上类似Lasso的自带特征选择)。

如图所示 [9],在ExtraTrees识别面部特征时,高亮的像素点代表更重要的特征。




2.3. 完全随机树嵌入(totally random trees embedding)

利用一个随机森林,进行无监督的特征转换,可以用于特征工程制造新特征。每一个样本,都可以被表示为它在每一棵树上的叶子的索引(index)。一共有n_estimators棵树,每棵树有2 ** max_depth个叶子(在一棵树上,每个样本只会属于一个叶子),所以新特征的维度是n_estimators * 2 ** max_depth。

相似的样本更可能被分类到相同的叶子上。这种变换方法可以看作一种无监督、非参数(non-parametric)的密度估计方法,它和流形学习也有一定关系。

Random trees embedding的一大特点,就是把低维的非线性特征,转化为高维的稀疏特征。这种特征转换能够极大改善线性分类器的性能。如下图所示,经过特征转换之后,朴素贝叶斯(Naive Bayes)也能生成非线性决策边界:[10]

代码实现:sklearn.ensemble.RandomTreesEmbedding - scikit-learn 0.18.1 documentation

参数解析:(其他参数参见随机森林)

sparse_output:如果为True,则返回一个csr矩阵;如果为False,则返回一个密集矩阵。



2.4. 用随机森林进行特征转换

基本思路:把低维度的非线性密集特征,转化为高维度的稀疏特征。

上文中,我们已经使用了无监督的totally random trees embedding。事实上,我们还可以使用其他类型的决策树集成,如随机森林和boosted trees。下图是各类算法组合和ROC曲线:[11]

可见,随机森林/boosted trees特征转换+线性回归的效果普遍好于单独的随机森林/boosted trees。

参考资料:

[1] Reference - scikit-learn 0.18.1 documentation

[2] scikit-learn原版英文文档:1.11. Ensemble methods

[3] L. Breiman, “Pasting small votes for classification in large databases and on-line”, Machine Learning, 36(1), 85-103, 1999.

[4] L. Breiman, “Bagging predictors”, Machine Learning, 24(2), 123-140, 1996.

[5] T. Ho, “The random subspace method for constructing decision forests”, Pattern Analysis and Machine Intelligence, 20(8), 832-844, 1998.

[6] G. Louppe and P. Geurts, “Ensembles on Random Patches”, Machine Learning and Knowledge Discovery in Databases, 346-361, 2012.

[7] Single estimator versus bagging: bias-variance decomposition

[8] Plot the decision surfaces of ensembles of trees on the iris dataset

[9] Pixel importances with a parallel forest of trees

[10] Hashing feature transformation using Totally Random Trees

[11] Feature transformations with ensembles of trees

编辑于 2017-05-04 05:21