本文是sklearn官网文档中集成模型一文的翻译,加入了自己的理解,翻译中难免有误,仅作参考。
集成学习的目标是结合一组基学习器的预测构建学习算法来提高单个学习器的普遍性和健壮性。
通常有两种方法:
- averaging:构建一组相互独立的学习器求预测的均值。由于方差的减小,组合学习器的性能比任何单个学习器都好。(eg:bagging,随机森林)
- boosting:基学习器串行组合,试图减小组合学习器的偏差,把几个弱学习器组合成一个强力的集成模型。(eg:adaboost,Gradient Tree Boosting)
1. bagging
集成算法中,bagging在原始训练集的随机子集上构建了几个黑盒学习器,聚合各自的预测形成最终的预测。通过在构建过程中引入随机化然后集成的方法来减小基学习器的方差(例如决策树)。由于提供了一种减少过拟合的方法,bagging更适用于强学习器(eg,developed decision tree),而boosting更适用于弱学习器(eg,shallow decision tree)。
bagging有很多种类,但由于划分随机子集方法的不同,不同的模型也都不一样:
- 当数据集的随机子集被划分为样本的随机子集时,则该算法被称为Pasting。
- 当抽取样品时,该方法称为Bagging 。
- 当数据集的随机子集被划分为特征的随机子集时,则该方法被称为random subspaces。
- 当基本估计器建立在样本和特征的子集上时,该方法被称为random patches。
在sklearn中,bagging用统一的BaggingClassifier元分类器提供。以用户指定的基学习器及制定划分随机子集的策略的参数作为输入,特别地,max_samples 和 max_features控制子集的尺寸,bootstrap和bootstrap_features控制是否抽出样本和特征。当使用可用样本的子集时,可以通过设置是否用包外样本来估计准确率oob_score=Ture,下面的代码说明了怎样用K近邻分类器的集成模型,每个基学习器建立在50%样本和50%特征的随机子集上。
from sklearn.ensemble import BaggingClassifier
from sklearn.neighbors import KNeighborsClassifier
bagging = BaggingClassifier(KNeighborsClassifier(),
max_samples=0.5, max_features=0.5)
note:回归问题上,学习器的均方误差可以分为偏差(bias)、方差(variance)、噪音(noise)三项。偏差刻画了不同学习器的预测能力,即模型本身的精确度,方差刻画了学习器在数据扰动时的多样性,即模型的稳定性,噪音刻画了数据变化带来的不可避免的误差。想要一个小的偏差,需要复杂化模型,增加模型参数,此时方差增大,且容易过拟合,想要小的方差,需要简化模型,减少模型参数,此时偏差增大,且容易欠拟合。由此,bias和variance往往是不能兼得的,造成这种现象的根本原因是,我们总是希望试图用有限训练样本去估计无限的真实数据。Bias与Variance两者之间的trade-off是机器学习的基本主题之一,可以在各种机器模型中发现它的影子。
2.决策树的bagging
sklearn.ensemble模块包括了两个基于随机决策树的averaging算法:randomForest和Extra-Trees。这两种算法都是专门为树设计的扰动组合技术。通过在分类器构造中引入随机性来创建一组不同的分类器。集成模型的预测是每个分类器的平均输出。
forest分类器必须配备两个矩阵:大小为[n_samples,n_features]的稀疏或密集矩阵X保存训练样本,大小为[n_samples]的矩阵Y保存训练样本的目标值
from sklearn.ensemble import RandomForestClassifier
X = [[0, 0], [1, 1]]
Y = [0, 1]
clf = RandomForestClassifier(n_estimators=10)
clf = clf.fit(X, Y)
和决策树一样,forest也可以扩展到多输出问题,(Y是大小为[n_samples,n_outputs]的数组)
2.1 随机森林
在随机森林中,(RandomForestClassifier和RandomForestRegressor类),集成模型中的每个树都是从训练集中替换抽取的样本构建的(自主采样)。另外,在树的构建期间分割节点时,选择的分割不再是所有特征的最佳分割,而是特征的随机子集的最佳分割。由于这种随机性,forest的偏差通常会略微增加(相对于单个随机树的偏差),但由于平均,方差也减小了,通常大于补偿的偏差增加,从而产生更好的模型。
与原始模型相反,sklearn实现通过对分类器的概率预测进行平均而不是让每个分类器对但各类进行投票组合。
2.2 极端随机森林
极端随机森林中(ExtraTreesClassifier和ExtraTreesRegressor类),随机性被进一步分离计算。与随机森林一样,使用候选特征的随机子集,但不是寻找最优判别属性,而是为每个候选特征随机选择阈值,并将随机生成的阈值的最佳值作为分割原则。这通常会更多地减少模型的方差,牺牲偏差,让偏差增加:
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_blobs
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.tree import DecisionTreeClassifier
X, y = make_blobs(n_samples=10000, n_features=10, centers=100,
random_state=0)
clf = DecisionTreeClassifier(max_depth=None, min_samples_split=2,
random_state=0)
scores = cross_val_score(clf, X, y)
scores.mean()
clf = RandomForestClassifier(n_estimators=10, max_depth=None,
min_samples_split=2, random_state=0)
scores = cross_val_score(clf, X, y)
scores.mean()
clf = ExtraTreesClassifier(n_estimators=10, max_depth=None,
min_samples_split=2, random_state=0)
scores = cross_val_score(clf, X, y)
scores.mean() > 0.999
2.3 参数
使用这些模型时需要调节的主要参数是n_estimators和max_features.前者是森林的树木数量,越大越好,但计算时间也会越长。另外注意,超过关键数量的树木,结果将会停止显著改善。后者是分割节点时要考虑的特征的随机子集的大小。方差减小更小更好,而偏差增加更好。对于回归问题,经验默认max_features=n_features,对于分类问题,max_features=sqrt(n_features),n_features是数据特征数目。通常max_depth=None,min_samples_spilt=1。这些值通常不是最佳的,并且可能导致消耗大量RAM,最好的参数值应该是始终交叉验证的,另外注意,在随机森林中,默认使用抽样样本bootstrap=True,而极端随机森林中默认是使用整个数据集bootstrap=False。当使用抽样样本时,可以在包外样本上估计泛化精度,设置oob_score=True.
2.4 并行化
最后,该模块还可以通过设置n_jobs进行树的并行构建和预测的并行计算。如果n_jobs=k,计算被划分为k个作业,在计算机的k个线程运行。如果n_jobs=1,可以使用所有线程。请注意,由于进程间通信开销,加速可能不是线性的,使用k个线程并不会k倍那么快。建立大量的树或构建耗时长的单个树时,仍可以实现显著的加速。
2.5 特征重要性评估
用树中决策节点的特征的相对等级(即深度)可用于评估该特征相对于目标变量的可预测性的相对重要性。树上端的特征给最终预测决策贡献了更大的分数。因此,他们贡献的样本的预测分数可以用作对特征的相对重要性的评估。
通过在几个随机树中平均化这些期望活动率可以 减少估计的方差,并将其用作特征选择。
实践中,这些估计值作为feature_importances_属性.正值,总和为1.值越高,匹配特征对预测函数的贡献越重要。
RandomForestClassifier方法
Parameter:
- n_estimators :默认为10,森林中树的数量
- criterion:默认 为‘gini’,分割属性的标定函数,gini基尼不纯度或entropy信息增益
- max_features:寻找最佳分割的特征数目,默认‘auto’
- int:每次分割时考虑int个特征
- float:百分比,int(max_features * n_features)
- auto:max_features=sqrt(n_features)
- sqrt:和auto一样
- log2:max_features=log2(n_features)
- None:max_features=n_features
- max_depth:默认None,树的最大深度,如果为None,则节点扩展直至叶子节点划分完或小于min_samples_split ,样本量少时可以不管
- min_samples_split:默认为2,分割内部节点时要求的最小样本数目,样本量少时可以不管
- min_samples_leaf:默认为1,叶子节点要求的最小样本数目,样本量少时可以不管
- min_weight_fraction_leaf :默认0,叶子节点所有样本权重和的最小值。为0表示不考虑权重问题,样本有相同权重。
- max_leaf_nodes:默认为0,最大叶子节点数,加了限制会在最大数内用最佳搜索方式展开树,防止过拟合
- min_impurity_split:节点最小不纯度,大于该值则继续分裂,否则成为叶子节点
- bootstrap:自主采样,默认True,极端随机森林默认为false
- oob_score:默认false,是否采用包外样本估计泛化精度
- n_jobs:计算的线程数
- warm_start:默认false,true表示复用之前的方法添加更多的学习器到集成模型中
3.Adaboost
sklearn.ensemble模块包括了流行的提升算法,Adaboost。
Adaboost的核心原则是在数据的反复修改版本上适应一系列弱学习器(仅比随机猜测略好的模型,如小决策树),然后将所有这些预测通过加权多数表决(或总和)合并产生最终预测。在每一个提升迭代的数据修改由每个训练样本施加权重的W1,W2,。。。Wn组成。最初,这些权重都被设置为1/N,所以第一步只是训练弱学习器的原始数据。对于每个连续的迭代,样本权重被单独修改,并将学习算法重新应用于重新加权的数据。在给定的步骤,那些在前一步骤导致提升模型不正确预测的训练样本的权重增加,而正确预测的训练样本的权重则会降低。随着迭代的进行,难以预测的示例将会受到越来越大的影响。因此,每个随后的弱学习器强制关注先前的错误样本。
3.1 用法
下面的例子展示了怎样配置100个弱学习器的Adaboost分类器
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
from sklearn.ensemble import AdaBoostClassifier
iris = load_iris()
clf = AdaBoostClassifier(n_estimators=100)
scores = cross_val_score(clf, iris.data, iris.target)
scores.mean()
弱学习器的数量由参数n_estimators控制,参数learning_rate控制弱学习器最后结合的贡献率。默认下,弱学习器是决策树。可以通过base_estimator参数制定不同的弱学习器。导致性能好坏的主要参数是n_estimators和基学习器的复杂度(比如它的深度max_depth和最小所需样本数min_samples_leaf)
AdaBoostClassifier方法
Parameter:
- base_estimator :default=DecisionTreeClassifier,梯度集成的基学习器
- n_estimators :default=50,学习器的最大数量,为了完美拟合,学习进程可能会早停
- learning_rate :default=1. ,学习率收缩每个学习器的贡献,learning_rate和n_estimators之间有一个平衡
- algorithm :{'SAMME', 'SAMME.R'}, optional (default='SAMME.R') real boosting algorithm.SAMME,discrete boosting algorithm.SAMME.R具有更快的收敛速度,用更少的迭代实现更小的误差
4. Gradient Tree Boosting
Gradient Tree Boosting或Gradient Boosted Regression Trees(GBRT)是任意可导损失函数提升模型的归纳。GBRT是一个准确有效的现成程序,可用于回归和分类问题。Gradient Tree Boosting模型可用于各种领域,包括web搜索排名和生态学。
GBRT的优点:
• 混合型数据的自然处理(异构特征)
• 预测强力
• 输出空间异常值的鲁棒性(强大的损失函数)
缺点:
• 由于boosting的本质而很难并行化
sklearn.ensemble模块提供了GBRT分类和回归的方法。
4.1 分类
GradientBoostingClassifier支持二分类和多分类。下面的例子展示了怎样配置100个决策树弱学习器的梯度提升分类器。
from sklearn.datasets import make_hastie_10_2
from sklearn.ensemble import GradientBoostingClassifier
X, y = make_hastie_10_2(random_state=0)
X_train, X_test = X[:2000], X[2000:]
y_train, y_test = y[:2000], y[2000:]
clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
max_depth=1, random_state=0).fit(X_train, y_train)
clf.score(X_test, y_test)
弱学习器的数量由参数n_estimators控制,每个树的尺寸由设定树的深度max_depth和最大叶子节点数max_leaf_nodes控制,learning_rate是0到1的超参数,通过收缩控制过拟合。
note:超过二分类的分类问题需要在每次迭代上归纳n_classes个回归树,由此,归纳树的总数是n_classes*n_estimators.所以,对于大量类别的数据集更推荐使用随机森林而非GBDT。
4.2 回归
GradientBoostingRegressor支持不同的损失函数用与回归,可以通过参数loss来指定,默认损失函数为最小二乘‘ls'
import numpy as np
from sklearn.metrics import mean_squared_error
from sklearn.datasets import make_friedman1
from sklearn.ensemble import GradientBoostingRegressor
X, y = make_friedman1(n_samples=1200, random_state=0, noise=1.0)
X_train, X_test = X[:200], X[200:]
y_train, y_test = y[:200], y[200:]
est = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1,
max_depth=1, random_state=0, loss='ls').fit(X_train, y_train)
mean_squared_error(y_test, est.predict(X_test))
下图展示了在在波士顿房价预测数据集上应用最小二乘误差和500个基学习器上的GradientBoostingRegressor的结果,每次迭代的训练误差储存在梯度集成模型中的train_score_属性中,staged_predict方法可以返回每个阶段的预测值,利用预测值可以得到每次迭代的测试误差。这样的图可以通过早停来决定n_estimators的数量。
通过feature_importances_属性显示特征的重要性。
程序代码:
params = {'n_estimators': 500, 'max_depth': 4, 'min_samples_split': 2, 'learning_rate': 0.01, 'loss': 'ls'}
clf = ensemble.GradientBoostingRegressor(**params)
clf.fit(X_train, y_train)
mse = mean_squared_error(y_test, clf.predict(X_test))
print("MSE: %.4f" % mse)
# compute test set deviance
test_score = np.zeros((params['n_estimators'],), dtype=np.float64)
for i, y_pred in enumerate(clf.staged_predict(X_test)):
test_score[i] = clf.loss_(y_test, y_pred)
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.title('Deviance')
plt.plot(np.arange(params['n_estimators']) + 1, clf.train_score_, 'b-', label='Training Set Deviance')
plt.plot(np.arange(params['n_estimators']) + 1, test_score, 'r-', label='Test Set Deviance')
plt.legend(loc='upper right')
plt.xlabel('Boosting Iterations')
plt.ylabel('Deviance')
4.3 控制树的尺寸
回归树基学习器的尺寸定义了梯度提升模型可以捕捉的变量交互的级别。一般来说,深度为h的树可以捕捉h阶的相互作用。这里有两种方法可以控制单个回归树的大小。
如果你指定max_depth=h,那么完全二进制树的深度为h。由此最多有2h个叶子节点和2h-1个分裂节点。
或者,你可以通过max_leaf_nodes参数指定叶子节点的个数来控制树的大小。这时,树将使用最佳优先搜索,其中不纯度提高最多的节点将首先扩大。max_leaf_nodes=k有k-1个分裂节点,进行max_leaf_nodes-1次迭代交互。
我们发现max_leaf_nodes=k提供与max_depth=k-1可比较的结果,以牺牲稍高的训练误差为代价得到更快的训练。
4.4 数学公式
GBRT使用下面的加法模型
hm(x)是集成模型中弱学习器的基函数。GBRT使用固定尺寸的决策树作为弱学习器。决策树具有即处理混合型数据的能力和对复杂功能建模的能力。
与其他提升算法类似,GBRT使用以前馈阶段方式构建添加模型:
在每个阶段,给定当前模型Fm-1及Fm-1(xi),选择决策树hm(x)来以最小化损失函数L
初始模型F0是问题特定的,对于最小二乘回归通常选择目标值的平均值。
梯度提升尝试通过最速下降解决这个最小化问题:最速下降方向是当前模型Fm-1评估的损失函数的负梯度,损失函数可以为任何可微分的损失函数:
使用行搜索来选择步长
GBRT分类与回归的算法仅是具体损失函数的不同。
4.4.1 损失函数
下列的损失函数可被支持用于loss参数中
- 回归
- 最小二乘'ls':由于较强的计算能力作为回归问题的自然选择。目标值的均值作为初始模型
- 最小一乘'lad':回归的一个健壮损失函数,目标值的中值作为初始模型
- Huber'huber':另一种健壮的损失函数,结合了ls和lad,用alpha控制离群点
- Quantile'quantile'
- 分类
- 二项式偏差'deviance':二分类的负二项式对数概率损失函数,提供了概率估计,对数几率作为初始模型
- 多项式偏差'deviance'
- 指数损失'exponential':Adaboost相同是损失函数,没有上面的损失函数健壮,仅用于二分类
4.5 正则化
4.5.1 收缩
提出一种简单的正则化策略,用v来标定每个弱学习器的贡献。
参数v也被称作学习率,因为它标定了梯度下降的步长,可以通过learning_rate设置。
参数learning_rate和参数n_estimators相互影响。learning_rate越小,需要n_estimators更大来保持恒定的训练误差。经验表明,小的学习率可以得到更好的测试误差。某文献推荐将学习率设置成一个小的常数(learning_rate<=0.1),然后通过早停来选择n_estimators。
4.5.2 子采样
某文献提出了一种将梯度提升和bagging(自主采样加平均投票)结合的随机梯度提升。每一次迭代,基函数采用训练集的子集subsample来训练。子集采样不是自主采样,通常选择subsample=0.5
下图说明了收缩和子采样对模型拟合的影响。我们可以清楚地看到,收缩比无收缩好,收缩、子采样可以进一步提高模型的准确性。另一方面,没有收缩的子采样,效果并不好。
随机梯度提升允许通过计算未包含在自主采样样本的样本偏差的改进来估计测试偏差的包外估计。这些存储在属性oob_improvement里。oob_improvement[i]如果将第i个阶段添加到当前预测中,则对OOB样本的损失进行估计。包外样本可用于模型选择,例如确定最佳迭代次数。OOB估计通常非常悲观,因此我们建议使用交叉验证,而只有在交叉验证太费时时才考虑使用OOB。
4.6 解释
通过简单的可视化树结构,可以轻松的解释单个决策树,然后,梯度提升树包含了几百个回归树,不能有效的可视化,幸运的是,已经有一些技术来总结解释梯度提升树。
4.6.1 特征重要性
特征通常不能有助于目标预测,在很多情形下,大多数特征都是不相关的,在解释模型时,第一个问题通常是,这些重要特征是什么,如何有助于预测目标。