0x00 集成学习
集成学习是通过训练弱干个弱学习器,并通过一定的结合策略,从而形成一个强学习器。有时也被称为多分类器系统(multi-classifier system)、基于委员会的学习(committee-based learning)等。
集成学习先产生一组“个体学习器”(individual learner),再用某种策略将它们结合起来。通常来说,很多现有的学习算法都足以从训练数据中产生一个个体学习器。
一般来说,我们会将这种由个体学习器集成的算法分为两类:
其中用的比较多的是同质学习器。同质学习器按照个体学习器之间是否存在依赖关系可以分为两类:
现在我们来简单评估一下集成学习方法的性能:考虑一个简单的例子,在二分类任务中,假定三个分类器在三个测试样本上的表现入下图所示,其中√代表正确,×代表分类错误,集成学习的结果则是由投票法(voting)决出,即“少数服从多数”:
在a图中每个分类器只有66.6%的精度的时候,集成学习达到了100%的精度;在b图中,三个分类器相同导致集成性能没有提高;c图中由于每个分类器的精度只有33.3%导致集成学习的效果变得更糟。由此我们可以看出来,集成学习中对个体学习器的要求应该是“好而不同”,即既满足准确性,又满足多样性(diversity),也即是说,学习器既不能太坏,而且学习器与学习器之间也要有差异。
随着集成中个体分类器数目T的增大,集成的错误率将指数级下降从而最终趋于0(这里还有一个前置条件就是个体分类器的错误率不能大于50%)。但我们曾假设各个分类器之间的错误率是相互独立的,而实际上再同一个任务中个体学习器视为解决同一个问题训练出来的,这也就意味着它们之间显然不可能相互独立。换句话说,个体学习器的“准确性”和“多样性”本身也是存在冲突的。一般的,准确性很高之后,若要增加多样性就需要准确性做出一定的牺牲。因此,如何产生“好而不同”的个体学习器,便是集成学习研究的核心。
目前,有三种常见的集成学习框架:bagging,boosting和stacking。国内,南京大学的周志华教授对集成学习有很深入的研究,其在09年发表的一篇概述性论文《Ensemble Learning》对这三种集成学习框架有了明确的定义,概括如下:
bagging:从训练集从进行子抽样组成每个基模型所需要的子训练集,对所有基模型预测的结果进行综合产生最终的预测结果:
boosting:训练过程为阶梯状,基模型按次序一一进行训练(实现上可以做到并行),基模型的训练集按照某种策略每次都进行一定的转化。对所有基模型预测的结果进行线性综合产生最终的预测结果:
stacking:将训练好的所有基模型对训练基进行预测,第j个基模型对第i个训练样本的预测值将作为新的训练集中第i个样本的第j个特征值,最后基于新的训练集进行训练。同理,预测的过程也要先经过所有基模型的预测形成新的测试集,最后再对测试集进行预测:
有了这些基本概念之后,直觉将告诉我们,由于不再是单一的模型进行预测,所以模型有了“集思广益”的能力,也就不容易产生过拟合现象。但是,直觉是不可靠的,接下来我们将从模型的偏差和方差入手,彻底搞清楚这一问题。
Boosting 是个非常强大的学习方法, 它也是一个监督的分类学习方法。它组合许多“弱”分类器来产生一个强大的分类器组。一个弱分类器的性能只是比随机选择好一点,因此它可以被设计的非常简单并且不会有太大的计算花费。将很多弱分类器结合起来组成一个集成的类似于SVM或者神经网络的强分类器。
现在我们知道boosting是组合多个弱学习器形成一个强学习器,那么一个自然而然的问题就是“boosting如何确定弱的规则?”为了发现弱的规则,我们可以应用不同分配下的基础的(机器)学习算法,每个算法都会生成一个弱规则,这是一个迭代的过程,多次迭代后,Boosting算法可以将它们组合成一个强大的决策规则。为了选择正确的分配方式,可以遵循下面几个步骤:
最后,将输出的多个弱学习器组合成一个强的学习器,提高模型的整体预测精度。Boosting总是更加关注被错误分类的弱规则。
Boosting算法的底层可以是任何算法,关于boosting算法,我们需要知道其中最有名的3个算法:
假设我们有一个分类问题,给定一个训练样本集,从这个分类问题中求出一个粗糙的分类规则(弱分类器)往往要比求一个精确的分类规则(强分类器)容易得多。提升方法便是从弱学习算法出发,反复学习得到一系列弱分类器(又称为基本分类器),然后通过组合这些弱分类器来构成一个强分类器。大多数的提升方法都是改变训练数据的概率分布(或说训练数据的权值分布),来针对不同的训练分布调用弱学习算法学习一系列弱分类器。这样一来,对于提升方法而言,就有了两个问题需要去解决:
AdaBoost针对第一个问题的做法是提高那些被前一轮弱分类器错误分类样本的权值,并降低那些被正确分类的样本的权值。经过一轮的权值加大后,后一轮的弱分类器就会更关注那些没有被正确分类的样本。持续下去,分类问题便会被一系列弱分类器“分而治之”。而对于第二个问题,即弱分类器的组合,AdaBoost采取加权多数表决法,具体的所,就是加大误差率小的弱分类器的权值,使其在表决中起更大的作用,另一方面,减小分类误差率大的弱分类器的权值,使其在表决中起较小的作用。
下面这张图对Ada-boost做了恰当的解释:
该原理可同样用于回归算法。它在不同权重的训练数据集上生成一系列的弱学习器,最开始的时候所有的数据拥有相同的权重,对于第一个分类器没有正确分类的点则在下一个决策器中的权重将会加大,作为一个迭代的过程,直到分类器数量达到预定值或预测精度达到预定值。大多数情况下,我们在AdaBoost中使用decision stamps。但是如果它可以接受带有权重的训练集,我们也可以使用其他任何的机器学习算法作为基础学习器。我们可以使用AdaBoost算法解决分类和回归问题。
Python 代码:
from sklearn.ensemble import AdaBoostClassifier # For Classification
from sklearn.ensemble import AdaBoostRegressor # For Regression
from skleran.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier()
clf = AdaBoostClassifier(n_estimators=100, base_estimator=dt, learning_rate=1)
# Above I have used decision tree as a base estimator, you can use any ML learner as base estimator if it accepts sample weight
clf.fit(x_train, y_train)
可以调整参数以优化算法的性能:
也可以调整基础学习器的参数以优化它自身的性能。
Gradient Boosting是一种Boosting的方法,它主要的思想是,每一次建立模型是在之前建立模型损失函数的梯度下降方向。这句话有一点拗口,损失函数(loss function)描述的是模型的不靠谱程度,损失函数越大,则说明模型越容易出错(其实这里有一个方差、偏差均衡的问题,但是这里就假设损失函数越大,模型越容易出错)。如果我们的模型能够让损失函数持续的下降,则说明我们的模型在不停的改进,而最好的方式就是让损失函数在其梯度(Gradient)的方向上下降。
广义的偏差(bias)描述的是预测值和真实值之间的差异,方差(variance)描述距的是预测值作为随机变量的离散程度。《Understanding the Bias-Variance Tradeoff》当中有一副图形象地向我们展示了偏差和方差的关系:
模型的偏差是一个相对来说简单的概念:训练出来的模型在训练集上的准确度。要解释模型的方差,首先需要重新审视模型:模型是随机变量。设样本容量为n的训练集为随机变量的集合(X1, X2, …, Xn),那么模型是以这些随机变量为输入的随机变量函数(其本身仍然是随机变量):F(X1, X2, …, Xn)。抽样的随机性带来了模型的随机性。
定义随机变量的值的差异是计算方差的前提条件,通常来说,我们遇到的都是数值型的随机变量,数值之间的差异再明显不过(减法运算)。但是,模型的差异性呢?我们可以理解模型的差异性为模型的结构差异,例如:线性模型中权值向量的差异,树模型中树的结构差异等。在研究模型方差的问题上,我们并不需要对方差进行定量计算,只需要知道其概念即可。研究模型的方差有什么现实的意义呢?我们认为方差越大的模型越容易过拟合:假设有两个训练集A和B,经过A训练的模型Fa与经过B训练的模型Fb差异很大,这意味着Fa在类A的样本集合上有更好的性能,而Fb反之,这便是我们所说的过拟合现象。我们常说集成学习框架中的基模型是弱模型,通常来说弱模型是偏差高(在训练集上准确度低)方差小(防止过拟合能力强)的模型。
基于boosting框架的整体模型可以用线性组成式来描述,其中
为基模型与其权值的乘积:
根据上式,整体模型的训练目标是使预测值F(x)逼近真实值y,也就是说要让每一个基模型的预测值逼近各自要预测的部分真实值。由于要同时考虑所有基模型,导致了整体模型的训练变成了一个非常复杂的问题。所以,研究者们想到了一个贪心的解决手段:每次只训练一个基模型。那么,现在改写整体模型为迭代式:
引入任意损失函数后,我们可以定义整体模型的迭代式如下:
Gradient Boosting是非常经典而又重要的提升方法,他与AdaBoost一样都是讲弱分类器合成强分类,但是其大致区别有:
Gradient Boosting中最有代表性的就是GBDT,该模型虽好,使用时理解数据以及正确调参才是王道
在Python Sklearn库中,我们可以使用Gradient Tree Boosting或GBDT(Gradient Boosting Descision Tree)。它是一个关于任意可微损失函数的一个泛化,可以用来解决分类和回归问题。
from sklearn.ensemble import GradientBoostingClassifier # For Classification
from sklearn.ensemble import GradientBoostingRegressor # For Regression
clf = GradientBoostingClassfier(n_estimators=100, learning_rate=1.0, max_depth=1)
clf.fit(X_train, y_train)
可以调整参数以优化算法的性能:
你可以调整损失函数以获得更好地性能。
XGBoost 是 “Extreme Gradient Boosting”的简称,是GBDT的一种高效实现,XGBoost中的基学习器除了可以是CART(gbtree)也可以是线性分类器(gblinear)。
Gradient Boosting Decision Tree从名称上来讲包含三个部分:Decision Tree、Boosting、Gradient Boosting。决策树我们都比较熟悉,在此略过不谈。Boosting这种方法,是指用一组弱分类器,得到一个性能比较好的分类器;这里用到的思路是给每个弱分类器的结果进行加权。Gradient Boosting是指使用gradient信息对分类器进行加权,之后的部分会详细介绍gradient加权的思路。综上,GBDT是一种使用gradient作为信息,将不同的弱分类decision trees进行加权,从而获得较好性能的方法。
GBDT的一般步骤:
在GBDT思想下,XGBoost对其中的步骤进行了具体实现。
Xgboost和GBDT的区别
XGBoost优势:
一般来说,Gradient Boosting(GB)方法适用于异质化数据。即,若你的数据集全由图片数据构成或者全由视频数据构成之类的,我们称其为同质化数据,这时使用神经网络往往会有更好的表现。但对于异质化数据,比如说数据集中有user gender,user age,也有content data等等的情况,GB方法的表现往往更好。GB方法比神经网络的入门门槛更低,使用起来也更简单。
NN和GB方法可以结合起来使用,并常常有很好的表现。我们可以使用NN方法学习embedding feature,并且和其他一些特征结合起来,再过GBDT。
参考链接: