R: реализация моего собственного алгоритма повышения градиента - PullRequest
10 голосов
/ 03 апреля 2020

Я пытаюсь написать собственный алгоритм повышения градиента. Я понимаю, что существуют такие пакеты, как gbm и xgboost,, но я хотел понять, как работает алгоритм, написав свой собственный.

Я использую набор данных 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

У меня есть несколько вопросов

  1. Правильно ли выглядит мой алгоритм повышения градиента?
  2. Правильно ли я рассчитал прогнозные значения yhats.mymod?

1 Ответ

0 голосов
/ 12 апреля 2020
  1. Да, это выглядит правильно. На каждом шаге вы подходите к псевдо-остаткам, которые вычисляются как производные потерь по отношению к соответствию. Вы правильно вывели этот градиент в начале своего вопроса и даже потрудились получить правильный коэффициент 2.
  2. Это также выглядит правильно. Вы агрегируете по моделям, взвешенным по скорости обучения, так же, как вы делали это во время обучения.

Но для решения того, что не было задано, я заметил, что у вашей системы обучения есть несколько причуд.

  • Набор данных iris разделен поровну между 3 видами (setosa, versicolor, virginica), и они являются смежными в данных. Ваши тренировочные данные содержат все сетозу и разноцветные, а набор тестов содержит все примеры virginica. Нет перекрытия, что приведет к проблемам вне выборки. Чтобы избежать этого, желательно сбалансировать наборы тренировок и тестов.
  • Комбинация скорости обучения и количества моделей кажется мне слишком низкой. Посадка сходится как (1-lr)^n. С lr = 1e-3 и n = 1000 вы можете моделировать только 63,2% величины данных. То есть, даже если каждая модель предсказывает каждую выборку правильно, вы оцениваете 63,2% правильного значения. Инициализация подгонки со средним значением, а не 0, поможет с тех пор, что эффект представляет собой регрессию к среднему значению, а не просто перетаскивание.
...