我有一个工作函数,它被编码为优化并行处理(希望如此)。我仍然不是最精通的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
。
最后,大多数gbm
生态学文献都遵循 Elith 等人描述的方法。2008 年“增强回归树的工作指南”,这是 BRT 功能dismo
的基础。出于本研究的目的,我想继续使用dismo
来构建gbm
模型。
我编写的函数测试了 和 的几种组合,tree.complexity
并learning.rate
为每个模型返回了几个性能指标的列表。然后我将所有这些组合lists
成一个data.frame
以便于排序。
函数的目标
- 从和
gbm
的每次迭代创建一个模型。tree.complexity
learning.rate
- 为创建的每个模型存储
$self.statistics$discrimination
、cv.statistics$discrimination.mean
、self.statistics$mean.resid
和。cv.statistics$deviance.mean
list
gbm
- 删除每个
gbm
模型以节省空间。 - 将每个列表组合成一种便于排序的格式。然后删除每个列表。
- 以优化并行处理以及减少计算时间和内存使用的方式执行上述所有操作。
可重现的示例
使用包中的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