我想使用foreach
函数运行一个大循环。这意味着使用%dopar%
运算符。
我找不到任何已完全解决此问题的问题。如果这是重复的,请指出我正确的方向,我将关闭这个问题。
我的成功喜忧参半。根据{{3}},它适用于我的机器上的简单示例,但是我似乎无法为自己的工作取得好成绩。
我的例子稍微复杂一点,所以魔鬼似乎一如既往的细节!我还阅读了包装创建者Revolution Analytics(help documentation)提供的“白皮书”。
我没有看到如何最好地使用.combine
参数将结果应用于我的全局输出列表。
我想将一个大的列表分配给一个大的列表,而不是使用cbind
或c
我的例子非常复杂,但如果我进一步简化它,那么任何答案都可能无法解决我的问题。
我将执行一种移动线性模型。所以使用lm()超过50个obersvations [1:50]拟合模型,预测第51个观察[51],将结果保存到列表中。
然后我将进一步转移所有观察。所以lm
超过[2:51]并预测第52次观察[52]。
我将总共使用100个观测值,因此我最多可以进行50次预测。
## ============================================ ##
## Setup the backend for the foreach function ##
## ============================================ ##
## doMC calls upon cores on demand, uses them and closes them
library(doMC)
registerDoMC(detectCores()) #detectCores() uses all cores
## for Windows users
#library(doParallel) --> for Windows users
#registerDoParallel(detectCores())
## ======================== ##
## Create some dummy data ##
## ======================== ##
## three columns, one hundred observations
my_data <- data.table(outcome = runif(100), V1 = 3*runif(100), V2 = sqrt(runif(100)))
## Have a look at the data if you like - using the DT package
library(DT)
datatable(my_data, options = list(pageLength = nrow(my_data)))
## ================================= ##
## Perform the loop the normal way ##
## ================================= ##
## Create container (a list of lists) for results
my_results <- sapply(c(paste0("step_", seq(1:50))), function(x) NULL)
step_results <- sapply(c("coefs", "rank", "error"), function(x) NULL)
for(i in 1:length(my_results)){my_results[[i]] <- step_results}
## Use a for loop to stpe through all the 50 'slices'
for(i in 1:50) { #max. 50 predictions possible
## Fit a linear model
my_fit <- lm("outcome ~ V1 + V2", data = my_data[i:(i+49)])
## Predict the next step
my_pred <- predict(my_fit, newdata = my_data[i+50, .(V1, V2)])
error <- my_data$outcome[i+50] - my_pred #simply measure the delta to the actual value
## Assign some results to the container created earlier
my_results[[i]][[1]] <- my_fit$coefficients
my_results[[i]][[2]] <- my_fit$rank
my_results[[i]][[3]] <- error
}
str(my_results) ## Keep this container to compare to our next one
## ============================================ ##
## Perform the loop using foreach and %dopar% ##
## ============================================ ##
## Create same results object for results as previously for parallel results
par_results <- sapply(c(paste0("step_", seq(1:50))), function(x) NULL)
step_results <- sapply(c("coefs", "rank", "error"), function(x) NULL)
for(i in 1:length(par_results)){par_results[[i]] <- step_results}
my_results_par <- foreach(i = 1:50) %dopar%
{ #max. 50 predictions possible
my_fit <- lm("outcome ~ V1 + V2", data = my_data[i:(i+49)])
my_pred <- predict(my_fit, newdata = my_data[i+50, .(V1, V2)])
error <- my_data$outcome[i+50] - my_pred
## Assign some results to the container created earlier
par_results[[i]][[1]] <- my_fit$coefficients
par_results[[i]][[2]] <- my_fit$rank
par_results[[i]][[3]] <- error
Sys.sleep(i/20) #Allows time to see R processes spawn on your system
return(par_results)
}
## We can see straight away that this didn't work as I would like it to
identical(my_results, my_results_par) #FALSE
## This shows that the output seems good on the surface
class(my_results_par)
length(my_results_par)
## This shows that it doesn't (WARNING: very long)
str(my_results_par)
您可以在.combine
函数中试用各种foreach
参数,例如:
foreach(i = 1:50, .combine = "c") {computation}
或
foreach(i = 1:50, .combine = "cbind") {computation}
这些产品分别是一个向量和一个矩阵,但不包含我试图在每个循环中保存的所有结果。
问题
.combine
参数创建所需的输出?我已经读过你可以为foreach
提供自定义功能......这可能是这样做的吗?我仍然不知道如何将结果合并。
答案 0 :(得分:1)
是的,这很容易做到。我们可以修改foreach
的代码 - 步骤如下,我们将data.table
包导出到每个工作人员。
my_results_par <- foreach(i = 1:50, .combine = append, .packages = c("data.table")) %dopar%
{
my_fit <- lm("outcome ~ V1 + V2", data = my_data[i:(i+49)])
my_pred <- predict(my_fit, newdata = my_data[i+50, .(V1, V2)])
error <- my_data$outcome[i+50] - my_pred
par_results <- list(
coefs = my_fit$coefficients,
rank = my_fit$rank,
error = error
)
par_results <- list(par_results)
names(par_results) <- paste0("step_", i)
return(par_results)
}
identical(my_results, my_results_par)
[1] TRUE