Почему важность распределяется после распараллеливания randomForest?
Сейчас я работаю с пакетом randomForest в R. Чтобы ускорить этап классификации, я был заинтересован в параллельном выполнении леса. Для этого я использовал пакет "foreach" аналогично тому, как он указан на виньетке "foreach". Это состоит в том, чтобы разделить общее количество деревьев на количество ядер, которые вы хотели бы использовать, и затем объединить их с функцией 'Объединить' пакета 'randomForest':
require(randomForest)
require(foreach)
require(doParallel)
registerDoParallel(cores=CPUS)
rf <- foreach::foreach(ntree=rep(ceiling(NTREE/CPUS), CPUS), .combine=randomForest::combine, .packages='randomForest') %dopar% {
randomForest::randomForest(x=t(Y), y=A, ntree=ntree, importance=TRUE, ...)
}
Я сравнил результаты "параллельного" леса с лесом, созданным в одном ядре. Возможности прогнозирования с помощью тестового набора, похоже, похожи, но значения "значимости" значительно снижены, и это влияет на следующие этапы выбора переменных.
imp <- importance(rf,type=1)
Я хотел бы знать, почему это происходит, и если это правильно или есть какая-то ошибка. Большое спасибо!
1 ответ
randomForest:: объединение не поддерживает пересчет важности переменной. В пакете randomForest важность вычисляется только перед завершением функции randomForest::randomForest. Два варианта:
Напишите свою собственную функцию переменной важности, которая будет использовать в качестве входных данных комбинированный набор леса и обучения. Это примерно ~50 строк кода.
Используйте параллельные вычисления типа lapply, где каждый объект randomForest является элементом в списке вывода. Затем суммируйте значение переменной по всем лесам и просто вычислите среднее значение. Вместо этого используйте do.call(rf.list, объединить) вне цикла foreach. Этот метод является приблизительным значением общей важности переменной, но довольно хорошим.
Пример поддерживаемого кода Windows:
library(randomForest)
library(doParallel)
CPUS=6; NTREE=5000
cl = makeCluster(CPUS)
registerDoParallel(cl)
data(iris)
rf.list = foreach(ntree = rep(NTREE/CPUS,CPUS),
.combine=c,
.packages="randomForest") %dopar% {
list(randomForest(Species~.,data=iris,importance=TRUE, ntree=ntree))
}
stopCluster(cl)
big.rf = do.call(combine,rf.list)
big.rf$importance = rf.list[[1]]$importance
for(i in 2:CPUS) big.rf$importance = big.rf$importance + rf.list[[i]]$importance
big.rf$importance = big.rf$importance / CPUS
varImpPlot(big.rf)
#test number of trees in one forest and combined forest, big.rf
print(big.rf) #5000 trees
rf.list[[1]]$ntree
#training single forest
rf.single = randomForest(Species~.,data=iris,ntree=5000,importance=T)
varImpPlot(big.rf)
varImpPlot(rf.single)
#print unscaled variable importance, no large deviations
print(big.rf$importance)
# setosa versicolor virginica MeanDecreaseAccuracy MeanDecreaseGini
# Sepal.Length 0.033184860 0.023506673 0.04043017 0.03241500 9.679552
# Sepal.Width 0.008247786 0.002135783 0.00817186 0.00613059 2.358298
# Petal.Length 0.335508637 0.304525644 0.29786704 0.30933142 43.160074
# Petal.Width 0.330610910 0.307016328 0.27129746 0.30023245 44.043737
print(rf.single$importance)
# setosa versicolor virginica MeanDecreaseAccuracy MeanDecreaseGini
# Sepal.Length 0.031771614 0.0236603417 0.03782824 0.031049531 9.516198
# Sepal.Width 0.008436457 0.0009236979 0.00880401 0.006048261 2.327478
# Petal.Length 0.341879367 0.3090482654 0.29766905 0.312507316 43.786481
# Petal.Width 0.322015885 0.3045458852 0.26885097 0.296227150 43.623370
#but when plotting using varImppLot, scale=TRUE by default
#either simply turn of scaling to get comparable results
varImpPlot(big.rf,scale=F)
varImpPlot(rf.single,scale=F)
#... or correct scaling to the number of trees
big.rf$importanceSD = CPUS^-.5 * big.rf$importanceSD
#and now there are no large differences for scaled variable importance either
varImpPlot(big.rf,scale=T)
varImpPlot(rf.single,scale=T)