Обучение случайной загрузке леса и генерация леса

У меня есть огромные тренировочные данные для случайного леса (dim: 47600811*9). Я хочу взять несколько (скажем, 1000) загрузочных выборок размером 10000 * 9 (принимая 9000 отрицательных классов и 1000 положительных точек данных класса в каждом прогоне) и итеративно генерировать деревья для всех из них, а затем объединить все эти деревья в 1 лес. Примерное представление о необходимом коде приведено ниже. Может ли кто-нибудь подсказать мне, как я могу сгенерировать случайную выборку с заменой из моих фактических данных поезда и оптимально сгенерировать для них деревья итеративно? Это будет большим подспорьем. Спасибо

library(doSNOW)
library(randomForest)
cl <- makeCluster(8)
registerDoSNOW(cl)

for (i=1:1000){
B <- 1000 
U <- 9000 
dataB <- trainData[sample(which(trainData$class == "B"), B,replace=TRUE),] 
dataU <- trainData[sample(which(trainData$class == "U"), U,replace=TRUE),] 
subset <- rbind(dataB, dataU)

Я не уверен, что это оптимальный способ создания подмножества снова и снова (1000 раз) из фактических данных trainData.

rf <- foreach(ntree=rep(125, 8), .packages='randomForest') %dopar% {
  randomForest(subset[,-1], subset$class, ntree=ntree)
}
}
crf <- do.call('combine', rf)
print(crf)
stopCluster(cl)

person Newbie    schedule 14.09.2016    source источник
comment
Вы пытались установить для аргумента sampsize randomForest меньшее значение? Установка меньшего sampsize и большего ntree может быть похоже на то, что вы делаете.   -  person Steve Weston    schedule 16.09.2016
comment
@ steve-weston Я пытаюсь создать подмножество фактических данных с помощью i = replicate(3, {c(sample(which(trainData$class == "B"), 50, replace = T), sample(which(trainData$class == "U"), 50, replace = T))}), а затем применить foreach rf <- foreach(ntree=rep(125, 8), .packages='randomForest') %dopar% {randomForest(trainData[i,-1], trainData[i,]$class, ntree=ntree, sampsize=rep(2,2))}, а затем объединить деревья с помощью crf <- do.call('combine', rf). Тогда я получаю только 1000 деревьев, а поскольку мой i содержит 3 подмножества, и для каждого подмножества я генерирую 1000 деревьев, я должен получить 3000 деревьев. Как это исправить?   -  person Newbie    schedule 17.09.2016
comment
В вашей программе есть ошибка, которую я описываю и исправляю в своем ответе.   -  person Steve Weston    schedule 18.09.2016


Ответы (2)


Хотя ваш пример распараллеливает внутренний, а не внешний цикл, он может работать достаточно хорошо, пока выполнение внутреннего цикла foreach занимает более нескольких секунд, что почти наверняка происходит. Однако в вашей программе есть ошибка: она отбрасывает первые 999 результатов foreach и обрабатывает только последний результат. Чтобы исправить это, вы можете предварительно выделить список длиной 1000 * 8 и назначать ему результаты foreach на каждой итерации внешнего цикла for. Например:

library(doSNOW)
library(randomForest)
trainData <- data.frame(a=rnorm(20), b=rnorm(20),
                        class=c(rep("U", 10), rep("B", 10)))
n <- 1000         # outer loop count
chunksize <- 125  # value of ntree used in inner loop
nw <- 8           # number of cluster workers
cl <- makeCluster(nw)
registerDoSNOW(cl)
rf <- vector('list', n * nw)
for (i in 1:n) {
  B <- 1000
  U <- 9000
  dataB <- trainData[sample(which(trainData$class == "B"), B,replace=TRUE),]
  dataU <- trainData[sample(which(trainData$class == "U"), U,replace=TRUE),]
  subset <- rbind(dataB, dataU)
  ix <- seq((i-1) * nw + 1, i * nw)
  rf[ix] <- foreach(ntree=rep(chunksize, nw),
                    .packages='randomForest') %dopar% {
    randomForest(subset[,-1], subset$class, ntree=ntree)
  }
}
cat(sprintf("# models: %d; expected # models: %d\n", length(rf), n * nw))
cat(sprintf("expected total # trees: %d\n", n * nw * chunksize))
crf <- do.call('combine', rf)
print(crf)

Это должно решить проблему, которую вы упомянули в комментарии, который вы мне адресовали.

person Steve Weston    schedule 18.09.2016
comment
Спасибо за подробный ответ. Я пробую это на своих реальных данных, посмотрим, сработает ли это. Большое спасибо. - person Newbie; 19.09.2016
comment
Я создал список 100 * 100, а затем сделал цикл для i = 1: 100, затем я генерирую (125 * 8) деревьев в каждом foreach. Я думаю, что я должен получить 125 * 8 * 100 = 100 000 деревьев, но на самом деле я получаю 1 250 000. Можете ли вы объяснить мне, почему это происходит? Спасибо. - person Newbie; 24.09.2016
comment
@Newbie Я завершил свой пример, чтобы вы могли запустить его самостоятельно. В процессе я исправил несколько проблем. Я неправильно вычислял длину списка результатов, потому что перепутал количество результатов и общее количество деревьев. - person Steve Weston; 26.09.2016
comment
Большое спасибо, Стив. - person Newbie; 28.09.2016

Что-то вроде этого будет работать

# Replicate expression 1000 times, store output of each replication in a list
# Find indices of class B and sample 9000 times with replacement
# Do the same 1000 times for class U. Combine the two vectors of indices

i = replicate(1000, {c(sample(which(trainData$class == "B"), 9000, replace = T), sample(which(trainData$class == "U"), 1000, replace = T))})

Затем подайте i в параллельную версию lapply.

mclapply(i, function(i, ntree) randomForest(trainData[i,-1], trainData[i,]$class, ntree=ntree)
person Vlo    schedule 14.09.2016
comment
Не могли бы вы подсказать мне, как я могу использовать эту параллельную версию lapply в вышеупомянутой команде foreach для вычисления деревьев для каждого i (подмножество из trainData), чтобы позже я мог объединить все деревья в лес. На самом деле мне нужно передать это i в эту строку кода в приведенном выше примере randomForest(subset[,-1], subset$class, ntree=ntree), первым аргументом будет весь подмножество данных вместо первого столбца, который равен class, а вторым аргументом будет столбец class этого подмножества данных. кадр. - person Newbie; 15.09.2016
comment
Я думаю, что вы предложили здесь заменить строку после %dopar%, то есть { randomForest(subset[,-1], subset$class, ntree=ntree) }, на {mclapply(i, function(i, ntree) randomForest(trainData[i,-1], trainData[i,]$class, ntree=ntree)}. Я прав? - person Newbie; 15.09.2016
comment
Я пробовал так rf <- foreach(ntree=rep(4,8), .packages="randomForest") %dopar% mclapply(i, function(i, ntree) randomForest(trainData[i,-1], trainData[i,]$class, ntree=ntree)), но выдает ошибку: task 1 failed - "could not find function "mclapply"" хотя простой тест функции mclapply работает: simplify2array(mclapply(rep(4, 5), rnorm, mc.preschedule = FALSE, mc.set.seed = FALSE)) - person Newbie; 15.09.2016
comment
@ Новичок Нет, вы не используете %dopar% с mclapply. dopar — это параллельная версия for loop, mclapply — это параллельная версия lapply. В R *apply фактически совпадает с for loop Что происходит, когда вы запускаете код дословно? У меня нет никаких данных, поэтому я не могу проверить код. - person Vlo; 15.09.2016
comment
Если я запускаю это так: rf <- mclapply(i, function(i, ntree) randomForest(trainData[i,-1], trainData[i,]$HepG2, ntree=rep(4,8))), то я получаю эту ошибку: Warning message: In mclapply(i, function(i, ntree) randomForest(trainData[i, -1], : all scheduled cores encountered errors in user code. Было бы лучше, если бы вы могли предложить мне, как я могу использовать этот фрагмент mclapply в моем исходном коде, указанном в вопросе. - person Newbie; 16.09.2016
comment
Не могли бы вы взглянуть на это. Спасибо - person Newbie; 16.09.2016