机器学习--有监督--GBM(Boosting)

集成学习(ensemble learning)是采用多个机器学习模型组合进行综合预测,从而提升模型性能的思路,分为bagging与boosting两种。之前学习的随机森林便是bagging的典型代表;而本次学习Gradient boosting machines为代表的boosting则是另一种集成思路。此外,集成学习使用的基学习器模型一般都是决策树(decision tree)。


1、bagging与boosting的区别

(1) bagging

  • 建立多个独立(independent)的、弱关联(de-correlated)、的base learner基学习器,每个单独的基学习器都是强学习器;
  • 进行预测结果时,综合考虑所有模型的预测值;即每个模型都有相同的权重,是平等的。
  • bagging适合于low bias and high variance,希望降低variance的情况;

(2) boosting

  • 建立一系列(sequential)的weak base learner基学习器。其中第一个base learner的性能仅仅由于随机猜测(random guessing),之后建立的模型都是在前一个模型的基础上通过调整参数(重点关注上一个模型预测最不准确地样本),从而逐渐提高后续模型的准确率。
  • 进行预测结果时,以每个基学习器的预测性能为权重(大致意思是性能优的基学习器有更高的话语权),综合考虑所有模型的预测值。
  • boosting适合于high bias and low variance,希望降低bias的情况。

2、GBM,Gradient boosting machines简单理解

2.1 Gradient descent

  • boosting的核心是以提高上一个模型性能为目的,建立一系列基学习器。而提升性能的标准可通过损失函数进行评价;而每一次提高性能的多少用学习率(learning rate)表示;


  • AdaBoost算法是早期boosting的流行形式之一,其使用SSE作为损失函数,即性能评价的标准。而GBM算法更加多元,它可以使用除SSE以外的其它指标作为损失函数;

The name gradient boosting machine comes from the fact that this procedure can be generalized to loss functions other than SSE.

2.2 GBM的超参数

GBM的超参数主要包含两类,一类是boosting相关的参数;一类是决策树本身的超参数

(1)boosting hyperparameters
  • Number of trees:首先是建立多少个基学习器。一般boosting需要建立较多数目(thousands)的决策树,从而提高后续模型的性能。但是过多的数目又可能带来过拟合的问题(bagging则不用担心这个问题)。
  • Learning rate:取值范围在0-1之间,一般取0.001~0.3。太大的学习率可能会使模型错过最佳的参数,从而导致过拟合;太小的值则可能需要建非常多的树,从而提高了计算资源与时间的需求。
    由于不同的学习率都有不同的最佳决策树的数目,所以不需要特别设置树参数,尽量取一个较大值即可。
(2)tree hyperparameters
  • 树的深度:一般建议取值范围在3~8;
  • 终端节点(terminal nodes)的最小样本数:一般建议取值范围在5~15;

超参数调整策略

  • 先确定最佳的学习率参数
  • 再调整决策树的相关参数

3、代码实操

示例数据:预测房价
ames <- AmesHousing::make_ames()
dim(ames)
## [1] 2930   81

set.seed(123)
library(rsample)
split <- initial_split(ames, prop = 0.7, 
                       strata = "Sale_Price")
ames_train  <- training(split)
# [1] 2049   81
ames_test   <- testing(split)
# [1] 881  81

  • 建模R包
library(gbm)
step1 : 先大致探索一下
set.seed(123) # for reproducibility
ames_gbm1 <- gbm(
  formula = Sale_Price ~ .,
  data = ames_train,
  distribution = "gaussian", # SSE loss function
  n.trees = 5000,
  shrinkage = 0.1,
  interaction.depth = 3,
  n.minobsinnode = 10,
  cv.folds = 10)

# find index for number trees with minimum CV error
best <- which.min(ames_gbm1$cv.error)
# [1] 1119

# get MSE and compute RMSE
sqrt(ames_gbm1$cv.error[best])
## [1] 22402.07

# plot error curve
gbm.perf(ames_gbm1, method = "cv")

如下可以看出在1119棵树的时候,交叉验证指标已经达到平台期


step2:学习率指标优化
# create grid search
hyper_grid <- expand.grid(
  learning_rate = c(0.3, 0.1, 0.05, 0.01, 0.005),
  RMSE = NA,
  trees = NA,
  time = NA
)
# execute grid search
for(i in seq_len(nrow(hyper_grid))) {
  # fit gbm
  set.seed(123) # for reproducibility
  train_time <- system.time({
    m <- gbm(
      formula = Sale_Price ~ .,
      data = ames_train,
      distribution = "gaussian",
      n.trees = 5000,
      shrinkage = hyper_grid$learning_rate[i],
      interaction.depth = 3,
      n.minobsinnode = 10,
      cv.folds = 10
    )
  })
  # add SSE, trees, and training time to results
  hyper_grid$RMSE[i] <- sqrt(min(m$cv.error))
  hyper_grid$trees[i] <- which.min(m$cv.error)
  hyper_grid$time[i] <- train_time[["elapsed"]]
}

dplyr::arrange(hyper_grid, RMSE)
#   learning_rate     RMSE trees  time
# 1         0.050 21807.96  1565 66.83
# 2         0.010 22102.34  4986 66.73
# 3         0.100 22402.07  1119 67.84
# 4         0.005 23054.68  4995 66.04
# 5         0.300 24411.95   269 64.84
  • 如上确定最佳的学习率参数为0.05。
step3:优化决策树参数
# search grid
hyper_grid <- expand.grid(
  n.trees = 5000,
  shrinkage = 0.05,
  interaction.depth = c(3, 5, 7),
  n.minobsinnode = c(5, 10, 15)
)

# create model fit function
model_fit <- function(n.trees, shrinkage, interaction.depth, n.minobsinnode) {
  set.seed(123)
  m <- gbm(
    formula = Sale_Price ~ .,
    data = ames_train,
    distribution = "gaussian",
    n.trees = n.trees,
    shrinkage = shrinkage,
    interaction.depth = interaction.depth,
    n.minobsinnode = n.minobsinnode,
    cv.folds = 10
  )
  # compute RMSE
  sqrt(min(m$cv.error))
}

# perform search grid with functional programming
hyper_grid$rmse <- purrr::pmap_dbl(
  hyper_grid,
  ~ model_fit(
    n.trees = ..1,
    shrinkage = ..2,
    interaction.depth = ..3,
    n.minobsinnode = ..4
  )
)
# results
dplyr::arrange(hyper_grid, rmse)
#   n.trees shrinkage interaction.depth n.minobsinnode     rmse
# 1    5000      0.05                 5             10 21793.28
# 2    5000      0.05                 3             10 21807.96
# 3    5000      0.05                 5              5 21976.76
# 4    5000      0.05                 3              5 22104.49
# 5    5000      0.05                 5             15 22156.30
# 6    5000      0.05                 3             15 22170.16
# 7    5000      0.05                 7             10 22268.51
# 8    5000      0.05                 7              5 22316.37
# 9    5000      0.05                 7             15 22595.51
  • 如上可以看出,最佳的决策树超参数组合:(1)interaction.depth=5;(2)n.minobsinnode = 10;
  • 但最佳组合的rmse值(21793)也仅比默认值(21807)降低了很少,所以决策树参数对GBM的影响相对较小。
step4:确定最佳模型,测试集评价
ame_gbm <- gbm(
  formula = Sale_Price ~ .,
  data = ames_train,
  distribution = "gaussian",
  n.trees = 5000,
  shrinkage = 0.05,
  interaction.depth = 5,
  n.minobsinnode = 10,
  cv.folds = 10)
(best <- which.min(ame_gbm$cv.error))
# [1] 1305
sqrt(ame_gbm$cv.error[best])
# [1] 22475.02

#自动调用最佳数目进行预测
pred = predict(ame_gbm, ames_test)
ModelMetrics::rmse(pred, ames_test$Sale_Price)
# [1] 20010.21

评价特征变量的重要性

vip::vip(ame_gbm) 

由于GBM是基于梯度下降的思路,当遇到非碗形的损失函数曲线时,有可能遇到局部的最低点local minimas,Stochastic gradient descent算法可采用抽样建模方式尽可能找到全局最低点;此外XGBoost可以尽可能避免boosting算法出现过拟合的情况。具体用法就暂不学习了~

你可能感兴趣的:(机器学习--有监督--GBM(Boosting))