上次文章中有介绍了决策树算法相关的理论,可以分为回归树和分类树。虽然决策树模型的结论容易理解,但是由于算法的能力有限,预测结果通常会被构建模型的训练集所影响,虽然我们可以通过剪枝的方法解决模型过度拟合训练数据集的问题,但是对于单个树模型来讲,预测的能力相对较弱,所以本次就将决策树算法提升至集成算法的层次,从而使我们在使用决策树模型时拥有更好的预测效果。
一、随机森林
1、boostsrap自助抽样
在介绍随机森林的产生步骤前,我们需要学习一下关于boostrap自助抽样。简单来说,boostrap自助抽样是一种样本内抽样的方法,即将样本看作总体并从中进行抽样,且属于又放回的抽样方法。具体的步骤:在含有 m 个样本的数据集中,每次随机挑选一个样本, 将其作为训练样本,再将此样本放回到数据集中,这样有放回地抽样 m 次,生成一个与原数据集大小相同的数据集,至于得到的数据集就可以用于训练模型。
由于是随机地有放回抽样组成的训练数据集,那么有可能有些样本在训练集中出现多次,有些则可能从未出现。这里可以假设总样本中共有S个数据,那么每个数据样本被抽中的概率是1/S,经过S次的抽取组成数据量为S的数据样本。也可推导如果一个样本S次抽取也抽不中的概率是(1-1/S)^S,当S趋于无穷时,概率趋于1/e,即为0.368。换而言之,会有大概三分之一的数据样本是不会被抽中作为训练数据集的,因此这些未出现在新数据集中的样本作为验证集,得到每个训练数据集所训练模型的均方误差,并且计算所有模型误差的平均值作为模型的验证误差。
2、随机森林的生成步骤
(1).从原始训练数据集中,应用bootstrap方法有放回地随机抽取K个新的自助样本集,这K个数据集作为构建K个决策树模型的数据源。而训练集采取这种随机有放回的抽样方法,使得训练样本之间并不是相互独立的,树模型的构造也不会过于片面。
(2).假定整个数据集有N个特征,对于每个训练数据集,我们都随机抽取n个特征(n<N)作为训练集树模型的特征变量,且对于K个训练集,用于训练的特征数量n是固定不变的。由于随机的特征增加树的独立性,K个树模型都需要最大可能地生长而不剪枝。
(3).通过对所有的决策树进行加权来预测新的数据,对于分类预测时,采用各决策树模型结果投票,而回归预测时,则对各树模型的结果取平均值。
3、袋外错误率
随机森林由于训练样本是随机抽样而成,特征变量也是随机抽样而成,以此体现其随机的特点。但是一个有意义的模型是要有稳定性,也就是我们虽然可以通过"随机"得到多个随机森林的模型,但我们只会选择一个最优的,而选择的标准就是袋外错误率,错误越低,说明该森林模型更优。
首先在bootstrap自助抽样下会有大约三分之一的数据没有被抽中,该数据称为袋外数据(obb)。比如对于第K个训练集,得到树模型K,没有包含在第K个训练集中的其他数据样本,我们就称这些数据样本为树模型K的obb样本。计算袋外错误率有下面的步骤:
(1).对于总样本下的每个样本,计算它作为obb样本的树模型对其的分类结果。
(2).然后汇总各树模型的结果,以简单多数投票作为该样本的分类结果。
(3).用误分个数占样本总数的比率作为整个随机森林的袋外错误率。
袋外错误率能够帮助我们选择更好的随机森林模型,而由于bootstrap自助法抽取训练集我们是没有办法干预的,而唯一能够我们能主动影响模型的就是指定模型特征变量的数量,也是说如果我们能指定较准确的特征数量,模型的袋外错误率也就会减少,反之如果我们看到袋外错误率比较小时,此时对应的特征数量也是比较适用于随机森林模型的。
4、随机森林模型的优缺点
优点:(1).避免了数据的过渡拟合现象
(2).擅长处理高维度的数据集,不用对数据集的特征作选择。
(3).对于不平衡数据集来说,随机森林可以平衡误差。
(4).随机森林算法有很强的抗干扰能力,数据样本存在大量的缺失时模型也不会失效。
缺点:(1).对小量数据集和低维数据集的分类不一定可以得到很好的效果。
(2).随机森林在解决回归问题时,并不 能给出一个连续的输出。
(3).由于随机森林自带的"随机性",无法控制模型内部的运行,只能在不同的参数和随
机种子之间进行尝试。
(4).执行数据虽然比boosting等快(随机森林属于bagging),但比单决策树。
二、梯度提升树
下面就介绍另外一种引入集成算法GBDT的决策树模型——梯度提升树模型,而这个模型与随机森林不同,该模型中的树模型是回归树模型。在这里简单地描述一下梯度提升树思路:与随机森林采用抽样构建多个树模型,梯度提升树一开始就使用全部的数据构建回归树模型,由于树模型最终会输出各个区域中的均值,于是我们就可以计算每个区域中的原始数据与该均值的差值,即残差,用这些残差继续建立新的回归树模型。新的模型树也会产生残差,重复之前的步骤,直至到残差小于给定的阈值或者迭代次数达到了指定的次数时停止。经过多次的迭代,得到的模型其实也是包含多个回归树模型的,如果此时我们向模型输入新的数据,则输出的结果为各个回归树的结果之和。下面通过几个方面的介绍,逐步了解GBDT算法的思想和原理。
1、提升树模型及其算法
提升法的原理是采用加法模型与前向分布算法,而提升树模型则是在此基础上,以决策树为基函数的提升方法。简单理解就是提升树模型就是众多决策树模型的加法模型,且可表示为:
其中,
其中,
其实我们从上面看到,影响提升树模型参数只有每次迭代所使用的损失函数,比如回归提升树模型就是采用一般的残差损失函数。而我们这次学习的GBDT是采用了最速下降法,下面继续学习GBDT算法。
2、GBDT的负梯度拟合
GBDT算法的引入,就是为了更方便地寻找损失函数的损失量达到最小值的时机。因为对于一般的损失函数,对每次迭代模型进行优化并不容易。因此Freidman提出梯度提升,也是我们GBDT的核心。首先我们需要确定损失函数是可微的,因为梯度其实就是指函数的微分。其次在单变量中,梯度表示函数在某个给定点的切线的斜率;在多变量中,梯度是一个向量,向量有方向,梯度的方向就指出了函数在给定点的上升最快的方向。但是我们的目标是求最小值,因此梯度的反方向就是函数在给定点下降最快的方向。利用这种最速下降法的近似方法,将损失函数的负梯度在模型的取值作为回归树的残差近似值,从而进行迭代得到下一个回归树模型,残差的近似值可表示为:
上面的微分式子中的负号就是表示梯度相反的方向,也就是负梯度。
3、GBDT算法过程
既然已经了解GBDT是利用损失函数的负梯度拟合每次回归树模型残差,从而迭代下一棵树。下面就详细地过一遍GBDT回归树的算法过程:
(1).输入训练数据集,假设数据集T={(X1,Y1),...(XN,YN)},设定最大的迭代次数为M,损失函数为L(y,f(x)),f(x)是指某一轮迭代的树模型拟合得到的结果。首先定义初始树模型:
(2).使用最速下降法计算每次迭代后回归树模型的残差拟合值,其中i为1,2...N,m为当前的迭代次数,最大值为M:
对
(3).之后更新第m次迭代得到的树模型,
(4).输出最终GBDT回归树模型,是由M次迭代所构建的m可回归树模型组成:
4、GBDT常用损失函数
下面为大家汇总一下回归树算法中常用到的损失函数:
(1).均方误差
(2).绝对损失
上面两种损失函数对应的负梯度误差为:
其中sign为符号函数,当y-f(x)小于0时输出-1,等于0时输出0,大于0时输出1。
(3).Huber损失
结合了均分误差和绝对损失两者的特点,对那些远离中心的异常点,损失函数会采用绝对损失,而中心附近的点采用均分误差。对于中心点的远近,一般使用分位数点度量。具体的函数形式如下:
δ 是 Huber损失函数的参数,称为超参数。超参数是在学习过程开始之前设置其值的参数,这里的δ 的取值取决于对异常单的定义。根据不同的残差绝对值大小,选用不一样的损失函数。Huber损失函数的负梯度误差为:
(4).Log-Cosh损失
Log-Cosh损失采用的计算方法是预测误差的双曲余弦的对数,形式如下:
Log-Cosh损失基本类似均分误差,但不容易受异常单的影响。
(5).分位数损失
分位数回归的目标在于估计给定预测值的条件分位数。实际上分位数回归就是平均绝对误差的一种拓展。分位数值的选择在于我们是否希望让正的或者负的误差发挥更大的价值。损失函数会基于分位数
同样上面
对于Huber损失和分位数损失,两者的作用都是在于减少异常点对损失函数的影响。
5、GBDT算法的优缺点
优点:(1).预测精度高,可以灵活处理各种类型的数据,包括连续值和离散值。
(2).使用一些健壮的损失函数,能减少异常值的影响。
(3).在相对少的调参时间情况下,预测的准备率也可以比较高。
缺点:(1).由于弱学习器之间存在依赖关系,难以并行训练数据。
(2).如果数据维度较高时会加大算法的计算复杂度。
三、随机森林与GBDT提升树比较
1、随机森林是bagging思想和决策树的结合,而GBDT是boosting思想和决策树的结合。其中的bagging思想。bagging的主要思想是训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的;boosting的思想则是每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化。
2、随机森林可以是回归树,也可以是分类树,而GBDT只能由回归树构成。
3、随机森林是并行生成众多决策树模型的,而GBDT是按顺序串行生成的。
4、随机森林输出的结果是采用投票的结果,而GBDT则是采用将所有树预测结果进行累加。
5、随机森林对数据的异常值不敏感,而GBDT对异常值就非常敏感。
6、随机森林是通过减少模型的方差提供模型性能,而GBDT则是减少偏差。
四、R语言的算法实现
随机森林算法在R语言中的实现,可以借用randomForest拓展包。详细的函数使用方法可以参考:RandomForest
# 加载randomForest包
library("randomForest")
# 使用与上次决策树算法一致的数据集
# 创建训练数据集和测试数据集
set.seed(12345)
credit_rand <- data[order(runif(1000)), ]
credit_train <- credit_rand[1:900, ]
credit_test <- credit_rand[901:1000, ]
# 确认决策树的数量和每个树模型使用的属性个数
# 确定属性个数,通过计算不一样属性数量的树模型的错误率,选择最小值对应的数量
set.seed(123)
n = length(names(credit_train))-1
for(i in 1:n){
my_model = randomForest(default~.,data = credit_train,mtry = i)
err = mean(my_model$err.rate)
print(err)
}
# 由结果看应该选择15
接着选择合适的ntree的值,ntree是指定我们模型中决策树数量的参数。ntree的值设置过低会导致错误率偏高,但是ntree值过高时也会导致模型的复杂度升高,降低效率。因此,我在ntry为15的前提下,创建随机森林模型,并将模型错误率与决策树数量的关系进行可视化:
my_model = randomForest(default~.,data = credit_train,mtry = 15,importance=T)
plot(my_model)
当ntree为100时,错误率基本是趋于稳定,所以ntree的参数为100。
# 确定模型
my_model = randomForest(default~.,data = credit_train,mtry = 15,ntree=100)
# 查看模型
my_model
可以知道我们的模型的袋外错误率为23.67%,我们可以通过importance函数查看各个变量的重要性:
最后我们可以使用这个初步模型的去预测一下测试数据集:
可以看到正确率为78%,相对于决策树模型,确实预测的效果会好一点,之后就是我们需要对模型进行优化了,优化的方案可以通过调整randomForest函数中的其他参数有实现,此处就不在叙述了。
梯度提升树算法在R语言中的实现,可以借用gbm拓展包,用于构建模型的核心函数是gbm(),下面就介绍该函数的关键参数:
·formula:常规的模型公式·distribution:损失函数的形式,分类问题可采用'bernoulli'或者'adaboost',回归问题选
择'gaussian'或者'laplace'·n.trees:迭代回归树的数量,一般来说先越大越好,然后选择合适的数目·shrinkage:学习速率,经验法则是设置shrinkage参数在0.01-0.001之间·data:数据集,数据框形式,标签不能用带有NA的,否则会出错·cv.folds:交叉验证法的则数,可以用来提取最适的回归树数目
同样地,我们对客户数据集构建预测模型,预测客户违约的可能:
# 加载gbm包
library(gbm)
set.seed(12345)
credit_rand <- data[order(runif(1000)), ]
# 因为gbm函数是识别0-1的分类指标
credit_rand$default=ifelse(credit_rand$default=='yes',1,0)
credit_train <- credit_rand[1:900,]
credit_test <- credit_rand[901:1000, ]
#构建模型
model=gbm(default~.,data =credit_train,distribution='adaboost')
#查看模型
summary(model)
从图中可以看到各变量在模型中相对重要的变量为job、credit_history等等。
# 预测
pre = predict(model,credit_test,n.trees = gbm.perf(model),type='response')
下面是模型在迭代的过程中,最佳的迭代次数是40多次,是由gbm.perf(model)返回的。
# 正确率
table(round(pre),credit_test$default)
当然后期也可以通过调整参数使模型变得更加准确,这里就不再叙述了。
这次学习的随机森林和GBDT算法,大概的流程和思想还是可以理解的,不过还有一些地方我还得慢慢去学习、理解和应用,希望之后能够逐步掌握它们ψ(*`ー´)ψ。