Параллельная функция выбора параметров R dismo :: gbm.step

У меня есть рабочая функция, которая закодирована для оптимизации параллельной обработки (надеюсь). Я все еще не очень хорошо разбираюсь в R, особенно в функциях и итерациях.

Я надеялся, что кто-то там сможет помочь мне оптимизировать функцию, которую я написал, вместе с дополнительным кодом, чтобы сократить время вычислений и полностью оптимизировать параметры параллельной обработки.

В частности, с использованием %do% vs %dopar% и перемещением дополнительного кода и функций параллельной обработки внутрь функции. Кажется, мне не удается заставить %dopar% работать, и я не уверен, что это проблема моего кода, R версии или конфликтующих библиотек.

Я был бы очень признателен за любые предложения о возможных способах более эффективного получения тех же результатов.

Фон:

Я использую dismo::gbm.step для построения gbm моделей. gbm.step выбирает оптимальное количество деревьев с помощью k-кратной перекрестной проверки. Однако параметры сложности дерева и скорости обучения по-прежнему необходимо установить. Я понимаю, что caret::train создан специально для этой задачи, и мне было очень интересно узнать о caret, особенно о возможностях адаптивной передискретизации. Однако мой ответ биномиальный, и caret не имеет возможности возвращать AUC для биномиальных распределений; Я хотел бы использовать AUC для копирования аналогичных опубликованных исследований в моей области (экология).

Я также использую dismo::gbm.simplify позже в анализе для выявления возможных сокращенных моделей. gbm.simplify полагается на данные, созданные при построении моделей в dismo, и я не могу заставить их работать с моделями, построенными в caret.

Наконец, большая часть литературы по экологии следует методам, описанным в Elith et al. 2008 "Рабочее руководство по усиленным деревьям регрессии", что и выполняет BRT в dismo основаны на. Для целей этого исследования я хотел бы продолжать использовать dismo для построения gbm моделей.

Написанная мною функция тестирует несколько комбинаций tree.complexity и learning.rate и возвращает список из нескольких показателей производительности для каждой модели. Затем я объединяю все lists в data.frame для облегчения сортировки.

Цель функции

  1. Создайте gbm модель из каждой итерации tree.complexity и learning.rate.
  2. Сохраняйте $self.statistics$discrimination, cv.statistics$discrimination.mean, self.statistics$mean.resid и cv.statistics$deviance.mean в list для каждой gbm созданной модели.
  3. Удалите каждую gbm модель, чтобы сэкономить место.
  4. Объедините каждый из списков в формат, позволяющий легко сортировать. Затем удалите каждый список.
  5. Выполните все вышеперечисленное таким образом, чтобы оптимизировать параллельную обработку, а также сократить время вычислений и используемую память.

Воспроизводимый пример с использованием набора данных Anguilla_train из пакета dismo

#Load libraries
require(pacman)
p_load(gbm, dismo, TeachingDemos, foreach, doParallel, data.table) 

data(Anguilla_train)

#Identify cores on current system
cores<-detectCores(all.tests = FALSE, logical = FALSE)
cores

#Create training function for gbm.step
step.train.fx=function(tree.com,learn){
  #set seed for reproducibility
  char2seed("StackOverflow", set = TRUE)
  k1<-gbm.step(data=Anguilla_train, 
               gbm.x = 3:13, 
               gbm.y = 2,
               family = "bernoulli", 
               tree.complexity = tree.com,
               learning.rate = learn,
               bag.fraction = 0.7,
               prev.stratify=TRUE,
               n.folds=10,
               n.trees=700,
               step.size=25,
               silent=TRUE,
               plot.main = FALSE,
               n.cores=cores)

  k.out=list(interaction.depth=k1$interaction.depth,
             shrinkage=k1$shrinkage,
             n.trees=k1$n.trees,
             AUC=k1$self.statistics$discrimination,
             cv.AUC=k1$cv.statistics$discrimination.mean,
             deviance=k1$self.statistics$mean.resid,
             cv.deviance=k1$cv.statistics$deviance.mean)  
  return(k.out)
}

#define complexity and learning rate
tree.complexity<-c(1:5)
learning.rate<-c(0.01,0.025,0.005,0.0025,0.001)

#setup parallel backend to use n processors
cl<-makeCluster(cores)
registerDoParallel(cl)

#Run the actual function
foreach(i = tree.complexity) %do% {
  foreach(j = learning.rate) %do% {
    nam=paste0("gbm_tc",i,"lr",j)
    assign(nam,step.train.fx(tree.com=i,learn=j))

  }
}

#Stop parallel
stopCluster(cl)
registerDoSEQ()

#disable scientific notation
options(scipen=999)

#Find all item in workspace that contain "gbm_tc"
train.all<-ls(pattern="gbm_tc")

#cbind each list that contains "gbm_tc"
train.results<-list(do.call(cbind,mget(train.all)))

#Place in a data frame
train.results<- do.call(rbind, lapply(train.results, rbind))
train.results <- data.frame(matrix(unlist(train.results),ncol=7 , byrow=T))

#Change column names
colnames(train.results)<-c("TC","LR","n.trees", "AUC", "cv.AUC", "dev", "cv.dev")

#Round 4:7
train.results[,4:7]<-round(train.results[,4:7],digits=3)

#Sort by cv.dev, cv.AUC, AUC
train.results<-train.results[order(train.results$cv.dev,-train.results$cv.AUC, -train.results$AUC),]

train.results

person GNG    schedule 26.04.2015    source источник
comment
У каретки есть возможность возвращать AUC для биномиальных распределений. См. twoClassSummary. Однако нелегко вернуть статистику, полученную из объекта модели (а не набора задержек пены).   -  person topepo    schedule 27.04.2015
comment
@topepo Макс, спасибо за ответ. Я был впечатлен, когда metric=ROC ответ может быть биномиальным, но должен быть фактором. При использовании predict не будет ли это возвращать строго двоичный результат (например, 0 или 1), или я ошибаюсь? Я следил за одним из ваших замечательных пошаговых руководств, в котором вы применяете это к mutagen набору данных, но не могу найти прямо сейчас. Я хотел бы вернуть положительную правильную дробь от 0 до 1; Я должен был упомянуть, что это для модели распространения видов. Кроме того, я полагаю, что если у меня слишком много caret конкретных вопросов, мне может потребоваться начать новый вопрос.   -  person GNG    schedule 27.04.2015
comment
Удалось ли вам наконец это оптимизировать? Я ищу такое же решение, но безрезультатно.   -  person 89_Simple    schedule 13.06.2018


Ответы (1)


Я все еще пытаюсь понять, как это сделать, а ты намного дальше меня! Одна вещь, которая приходит мне в голову, заключается в том, что проблема может быть во вложенных %do%s? В качестве теста, почему бы не попробовать %dopar% только для j или посмотреть, можно ли свернуть матрицу j & k в один вектор, возможно, список, содержащий перестановки обоих терминов, который будет передан в gbm.step? Например.

tree.complexity = i[1],
learning.rate = i[2],

Пожалуйста, дайте мне знать, если у вас есть успех!

Изменить: также другой потенциальный маршрут будет %:% от здесь.

foreach(tree.com = 1:5) %:% foreach(learn = c(0.01,0.025,0.005,0.0025,0.001)) %dopar% {
gbm.step ... return(list(...))}

Если вы добавите tree.com & learn в список, то потенциально он выдаст красивую матрицу этих значений. Другой вариант:

foreach(tree.com = 1:5, learn = c(0.01,0.025,0.005,0.0025,0.001) %dopar% {
    gbm.step ... return(list(...))}
person dez93_2000    schedule 01.03.2017