机器学习笔记9-集成学习
集成学习(ensemble learning)通过构建并结合多个学习器来完成学习任务。下图展示了集成学习的一般结构:先产生一组个体学习器,再用某种策略将它们结合起来。个体学习器通常由一个现有的算法从训练数据产生,如决策树算法、支持向量机算法等。关于如何产生并结合“好而不同”的个体学习器是集成学习研究的核心。集成学习通过将多个学习器进行组合,常可获得比单一学习器显著优越的泛化性能。
根据个体学习器的生成方式,目前的集成学习方法大致分为两类,即个体学习器间存在强依赖关系、必须串行生成的序列化方法,以及个体学习器间不存在强依赖关系、可同时生成的并行化方法;前者代表是Boosting,后者的代表是Bagging和“随机森林”。
-
Boosting
Boosting的工作机制是:先从初始训练集中训练出一个基学习器,再根据基学习器的表现对训练数据分布(权值)进行调整,使得先前基学习器做错的训练样本在后续受到更多关注,然后基于调整后的样本分布来训练下一个基学习器;如此反复进行,直至基学习器的数目达到事先指定的值T,最终将这T个基学习器进行加权结合。这其中,最具代表性的就是AdaBoost算法。AdaBoost包含以下步骤:
(1)初始化训练数据的权值分布
(2)对
(a)使用具有权值分布 的训练数据集学习,得到基分类器
(b)计算 在训练数据集上的分类误差率
(c)计算 的系数
(d)更新训练数据集的权值分布
(3)构建基分类器的线性组合
对AdaBoost算法作如下说明:步骤(c)中, 随着 的减小而增大,所以误分类率越小的基分类器在最终分类器中的作用越大;步骤(d)中,被基分类器误分类样本的权值得以扩大,而被正确分类样本权值得以缩小。因此误分类样本在下一轮学习中起更大作用。不改变所给的训练数据,而不断改变训练数据的权值分布,使得训练数据在基分类器的学习中起不同的作用,这是AdaBoost的一个特点。
__
AdaBoost算法还有另一个解释,即认为其模型为加法模型、损失函数为指数函数、学习算法为前向分布算法的二类分类学习方法。考虑加法模型 ,损失函数为 ,前向分布算法求解这一优化问题的想法是:从前向后,每一步只学习一个基函数,逐步逼近优化目标。具体操作如下:
(1)初始化
(2)对
(a)极小化损失函数
(b)更新
(c)得到加法模型 -
Bagging与随机森林
欲得到泛化性能强的集成,集成中的个体学习器应尽可能相互独立。给定一个训练数据集,一种可能的做法是对训练样本进行采样,产生出若干个不同的子集,再从每个数据子集中训练出一个基学习器。这样,由于训练数据的不同,获得的基学习器可望具有较大的差异。然而,为获得好的集成,我们同时还希望个体学习器不能太差。如果采样出的每个子集都完全不同,则每个基学习器只用到了一小部分训练数据,甚至不足以进行有效学习,这无法确保产生出较好的基学习器。为解决这个问题,可使用相互有交叠的采样子集。
__
(1)Bagging
Bagging是基于自主采样法(bootstrap sampling):给定包含m个样本的数据集,每次取出并放回一个样本,重复m次,于是初始训练集中约有63.2%的样本会出现在采样集中。照这样,可以采样出T个含m个训练样本的采样集,然后基于每个采样集训练出一个基学习器,再将这些基学习器进行结合。这就是Bagging的基本流程。在对预测输出进行结合是,Bagging通常对分类任务使用简单投票法,对回归任务使用简单平均法。假定基学习器的计算复杂度为 ,考虑到采样与投票/平均过程的复杂度很小,因此Bagging的复杂度与基学习器的复杂度同阶。另外,与AdaBoost只适用于二分类任务不同,Bagging可用于多分类、回归任务。
__
(2)随机森林(RF)
RF在以决策树为基学习器构建Bagging集成的基础上,进一步在决策树的训练过程引入随机属性。具体来说,传统决策树在选择划分属性时是在当前节点的属性集合中选择一个最优属性;而在RF中,对基决策树的每个结点,先从该结点的属性集合中随机选择一个包含k个属性的子集,然后再从这个子集中选择一个最优属性用于划分。Bagging中基学习器的“多样性”仅通过样本扰动带来不同,RF中基学习器的多样性不仅来自样本扰动,还来自属性扰动,这就使得泛化性能又提升一步。随机森林简单、容易实现、计算开销小,在很多现实任务中展现出强大性能。 -
结合策略
学习器结合会带来三方面好处:1. 提升泛化性能;2. 避免陷入局部极小;3. 扩大假设空间。一般有以下结合策略:
(1)平均法:包括简单平均法、加权平均法。
(2)投票法:包括绝对多数投票法、相对多数投票法、加权投票法。
(3)学习法:通过另一个学习器来进行结合。Stacking是学习法的典型代表。此时,个体学习器称为初级学习器,用于结合的学习器称为次级学习器。Stacking先从初级数据集训练出初级学习器,然后生成一个新数据集用于训练次级学习器。在这个新数据集中,初级学习器的输出被当做样例输入特征,而初始样本的标记仍被当作样例标记。在训练阶段,若直接用初级学习器的训练集来产生次级训练集,过拟合风险较大。因此一般是通过使用交叉验证法这样的方式,用训练初级学习器未使用的样本来产生次级学习器的训练样本。以k折交叉验证为例,将数据集分为 ,令 和 表示第j折的测试集和训练集,用 去训练基学习器,用 去生成次级训练样例。将k个次级训练样例的实例组合起来,便生成了一个与初始训练集数目相同的次级训练集。
集成学习能够有效地提升数据分类回归的准确率,因此在Kaggle的数据比赛中,这个算法几乎是标配。以下是利用集成学习(包含Stacking)实现的一段代码:
class StackingAveragedModels(BaseEstimator, RegressorMixin, TransformerMixin):
def __init__(self, base_models, meta_model, n_folds=5):
self.base_models = base_models #初级学习器
self.meta_model = meta_model #次级学习器
self.n_folds = n_folds #默认是5折交叉验证
def fit(self, X, y):
self.base_models_ = [list() for x in self.base_models]
self.meta_model_ = clone(self.meta_model)
kfold = KFold(n_splits=self.n_folds, shuffle=True, random_state=156)
out_of_fold_predictions = np.zeros((X.shape[0], len(self.base_models)))
for i, model in enumerate(self.base_models): #逐次训练初级学习器中的各个模型
for train_index, holdout_index in kfold.split(X, y):
instance = clone(model)
self.base_models_[i].append(instance)
instance.fit(X[train_index], y[train_index]) #训练利用的是训练集
y_pred = instance.predict(X[holdout_index]) #这一步利用的数据是测试集
out_of_fold_predictions[holdout_index, i] = y_pred
self.meta_model_.fit(out_of_fold_predictions, y)
return self
def predict(self, X):
meta_features = np.column_stack([
np.column_stack([model.predict(X) for model in base_models]).mean(axis=1)
for base_models in self.base_models_ ])
return self.meta_model_.predict(meta_features)
参考:
李航《统计学习方法》
周志华《机器学习》
https://www.kaggle.com/serigne/stacked-regressions-top-4-on-leaderboard