foreach而不是FOR IN R.

时间:2013-05-28 04:28:16

标签: r loops foreach parallel-processing

我是R的新生。我想在R中执行randomForest,数据有1000行和28列。我们的想法是测试所有mtry(1:27),每个mtry将通过10次重复10次CV测试。问题是需要这么长时间而且仍然没有结果!我尝试使用'foreach'循环而不是'for',但我不知道该怎么做。代码如下所示:

library(randomForest)
n <- nrow(data)
a1 <- 1:n
a2 <- rep(1:10,ceiling(n/10))[1:n]
k <- ncol(data)-1    
trainrf <- testrf <- list()
for(i in 1:k){    # tune mtry from 1 to 27
    rftrain <- rftest <- NULL
    for(x in 1:10){   # 10 repeats 10-fold CV
        set.seed(1981)
        a2 <- sample(a2,n)
        train.rf <- test.rf <- rep(0,10)
        for(j in  1:10){
            m <- a1[a2 == j]
            n1 <- n-length(m)
            n2 <- length(m)
            set.seed(2013)
            rf.data <- randomForest(level~., data=data[-m,], mtry=i, ntree=1000)
            train.rf[j] <- sum(data[-m,28] == predict(rf.data, data[-m,]))/n1
            test.rf[j] <- sum(data[m,28] == predict(rf.data, data[m,]))/n2
        }
        rftrain[x] <- mean(train.rf); rftest[x] <- mean(test.rf)
    }
    trainrf[[i]] <- rftrain; testrf[[i]] <- rftest
}

我的笔记本电脑是i7 Windows 7 64位,据我所知,我写了几个代码:

library(foreach)
library(doParallel)
cl <- makeCluster(4)
registerDoParallel(cl)

请帮助我,非常感谢!

2 个答案:

答案 0 :(得分:2)

你可能应该阅读一些foreach小插曲,因为虽然这是foreach的相当简单的使用,但它并非无足轻重,就像许多例子一样。

这是我尝试将您的脚本翻译为foreach,虽然我无法测试它,因为您的示例无法重现:

library(doParallel)
cl <- makeCluster(4)
registerDoParallel(cl)
n <- nrow(data)
a1 <- 1:n
a2 <- rep(1:10,ceiling(n/10))[1:n]
k <- ncol(data)-1
outercomb <- function(...) {
    lapply(1:2, function(i) lapply(list(...), function(p) p[[i]]))
}
innercomb <- function(...) {
    lapply(1:2, function(i) sapply(list(...), function(p) p[[i]]))
}
r <- foreach(i=1:k, .combine='outercomb', .multicombine=TRUE,
        .packages='randomForest') %:%
    foreach(1:10, .combine='innercomb', .multicombine=TRUE) %dopar% {
        set.seed(1981)
        Xa2 <- sample(a2, n)
        train.rf <- double(10)
        test.rf <- double(10)
        for(j in  1:10){
            m <- a1[Xa2 == j]
            n1 <- n-length(m)
            n2 <- length(m)
            set.seed(2013)
            rf.data <- randomForest(level~., data=data[-m,], mtry=i, ntree=1000)
            train.rf[j] <- sum(data[-m,28] == predict(rf.data, data[-m,]))/n1
            test.rf[j] <- sum(data[m,28] == predict(rf.data, data[m,]))/n2
        }
        c(mean(train.rf), mean(test.rf))
    }
trainrf <- r[[1]]
testrf <- r[[2]]

以下是一些评论:

  • 您应该调查caret包。我认为它可以很容易地为你做这种事情,它使用foreach并行完成。
  • 虽然我在外部两个循环中进行并行化,但如果您可以访问群集,则可能会更进一步。这里有很多并行性。
  • 这使用嵌套的foreach循环,这是一个高级功能,但对这类问题非常有用。
  • 我使用Xa2代替a2来强调foreach循环无法跨循环迭代更新变量a2。我不确定我的版本是否符合您的要求,因此您必须考虑这一点。
  • .combine函数有点棘手,但需要产生两个结果。他们都进行各种转置。
  • 你应该避免randomForest的公式接口,因为它使用更多内存并且可能很慢。
  • 我假设您使用set.seed仅用于测试。

答案 1 :(得分:0)

我无法执行您的示例,因为未定义data。但也许最小foreach - 示例可能会有所帮助:

library(foreach)
library(doParallel)
cl <- makeCluster(4)
registerDoParallel(cl)

testList <- foreach(i=1:5) %dopar% {
  1:i
}

i=1:5每次投放的结果会合并到一个列表中并保存在变量testList中:

> testList
[[1]]
[1] 1

[[2]]
[1] 1 2

[[3]]
[1] 1 2 3

[[4]]
[1] 1 2 3 4

[[5]]
[1] 1 2 3 4 5

您可以使用以下方法指定另一种合并方法:

> testList <- foreach(i=1:5, .combine="c") %dopar% {
+   1:i
+ }
> 
> testList
 [1] 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5

我认为你必须做两个foreach循环,一个用于trainrf,一个用于testrf