R:实现我自己的梯度提升算法

Posted

技术标签:

【中文标题】R:实现我自己的梯度提升算法【英文标题】:R: implementing my own gradient boosting algorithm 【发布时间】:2020-07-15 01:12:16 【问题描述】:

我正在尝试编写自己的梯度提升算法。我知道有像 gbmxgboost, 这样的现有软件包,但我想通过自己编写来了解算法的工作原理。

我正在使用iris 数据集,我的结果是Sepal.Length(连续)。我的损失函数是mean(1/2*(y-yhat)^2)(基本上是前面1/2的均方误差),所以我对应的梯度就是残差y - yhat。我将预测初始化为 0。

library(rpart)
data(iris)

#Define gradient
grad.fun <- function(y, yhat) return(y - yhat)

mod <- list()

grad_boost <- function(data, learning.rate, M, grad.fun) 
  # Initialize fit to be 0
  fit <- rep(0, nrow(data))
  grad <- grad.fun(y = data$Sepal.Length, yhat = fit)

  # Initialize model
  mod[[1]] <- fit

  # Loop over a total of M iterations
  for(i in 1:M)

    # Fit base learner (tree) to the gradient
    tmp <- data$Sepal.Length
    data$Sepal.Length <- grad
    base_learner <- rpart(Sepal.Length ~ ., data = data, control = ("maxdepth = 2"))
    data$Sepal.Length <- tmp

    # Fitted values by fitting current model
    fit <- fit + learning.rate * as.vector(predict(base_learner, newdata = data))

    # Update gradient
    grad <- grad.fun(y = data$Sepal.Length, yhat = fit)

    # Store current model (index is i + 1 because i = 1 contain the initialized estiamtes)
    mod[[i + 1]] <- base_learner

  
  return(mod)

有了这个,我将 iris 数据集拆分为训练和测试数据集,并让我的模型适应它。

train.dat <- iris[1:100, ]
test.dat <- iris[101:150, ]
learning.rate <- 0.001
M = 1000
my.model <- grad_boost(data = train.dat, learning.rate = learning.rate, M = M, grad.fun = grad.fun)

现在我从my.model 计算预测值。对于my.model,拟合值为0 (vector of initial estimates) + learning.rate * predictions from tree 1 + learning rate * predictions from tree 2 + ... + learning.rate * predictions from tree M

yhats.mymod <- apply(sapply(2:length(my.model), function(x) learning.rate * predict(my.model[[x]], newdata = test.dat)), 1, sum)

# Calculate RMSE
> sqrt(mean((test.dat$Sepal.Length - yhats.mymod)^2))
[1] 2.612972

我有几个问题

    我的梯度提升算法看起来正确吗? 我计算的预测值yhats.mymod 是否正确?

【问题讨论】:

【参考方案1】:
    是的,这看起来是正确的。在每个步骤中,您都在拟合伪残差,这些伪残差被计算为损失相对于拟合的导数。您在问题开始时已经正确导出了这个梯度,甚至费心得到正确的因子 2。 这看起来也正确。您正在对模型进行聚合,并按学习率加权,就像您在训练期间所做的那样。

但是为了解决一些没有被问到的问题,我注意到你的训练设置有一些怪癖。

iris 数据集在 3 个物种(setosa、versicolor、virginica)之间平均分配,并且这些物种在数据中是相邻的。您的训练数据包含所有 setosa 和 versicolor,而测试集包含所有 virginica 示例。没有重叠,这将导致样本外问题。最好平衡您的训练集和测试集以避免这种情况。 在我看来,学习率和模型数量的组合太低了。拟合收敛为(1-lr)^n。使用lr = 1e-3n = 1000,您只能对数据量级的 63.2% 进行建模。也就是说,即使每个模型都正确预测了每个样本,您也会估计正确值的 63.2%。用平均值而不是 0 初始化拟合会有所帮助,因为这样会产生对平均值的回归,而不仅仅是拖累。

【讨论】:

感谢您的 cmets。您能否详细说明“拟合收敛为 (1-lr)^n”的原因?这背后的原理是什么? 这是因为fit &lt;- fit + learning.rate * prediction,其中prediction是残差target - fit。所以fit &lt;- fit + lr * (target - fit),或fit &lt;- fit * (1 - lr) + target * lr。这只是一个指数移动平均线。根据Wikipedia,“在k 项之后停止所省略的权重是总权重中的(1-α)^k”(α 是学习率,kn)。您从 0 的估计值而不是平均值开始,因此忽略的权重直接来自预测。

以上是关于R:实现我自己的梯度提升算法的主要内容,如果未能解决你的问题,请参考以下文章

梯度提升树GBDT

梯度提升树GBDT

梯度提升分类树原理推导(超级详细!)

如何自己实现简单的Google深度学习框架TensorFlow?

Matlab基于极端梯度提升XGBoost实现分类预测(Excel可直接替换数据)

在 R 中使用 gbm 进行梯度提升,分布 =“bernoulli”