【问题标题】:Parallelization approach with parallel package seems to return an empty list并行包的并行化方法似乎返回一个空列表
【发布时间】:2017-09-07 17:55:57
【问题描述】:

在之前的讨论和 F.Privé 的帮助之后,我做了一些更改,以下代码实际上正在执行预期的操作。

library(purrr)
library(parallel)

p_list = list( "P1" = list( c("MAKM1","MMERMTD","FTRWDSE" )) , 
                  "P2" = list( c("MFFGGDSF1","DFRMDFMMGRSDFG","DSDMFFF")),
                  "P3" = list( c("MDERTDF1","DFRGRSDFMMG","DMMMFFFS")),
                  "P4" = list( c("MERTSDMDF1","SDFRGSSMRSDFG","DFFFM")))


chars <- set_names(c("M", "S", "M"), c("class.1", "class.35", "class.4"))

get_0_and_all_combn <- function(x) {
  map(seq_along(x), function(i) combn(as.list(x), i, simplify = FALSE)) %>%
    unlist(recursive = FALSE) %>% 
    c(0L, .)
}


get_pos_combn <- function(x, chars) {
  x.spl <- strsplit(x, "")[[1]] 

  isUni1 = grep("class.1", names(chars))
  isFirst = grepl("1",x)

  map2(.x=chars, .y=seq_along(chars), .f=function( chr, index ) {

    if( length(isUni1) != 0 ){
      if( index == isUni1 & isFirst == TRUE )
        1 %>% get_0_and_all_combn()
      else{
        which(x.spl == chr) %>%
          get_0_and_all_combn()
      }
    }else{
      which(x.spl == chr) %>%
        get_0_and_all_combn()
    }

  }) %>%
    expand.grid()
}


get_pos_combn_with_infos <- function(seq, chars, p_name) {
  cbind.data.frame(p_name, seq, get_pos_combn(seq, chars))
}

combine_all <- function(p_list, chars){

  i = 1
  fp <- as.data.frame(matrix(ncol = 5))
  colnames(fp) = c("p_name" ,"seq" , names(chars) )

  for(p in p_list){

    p_name = names(p_list)[i]

    for(d in 1:length(p[[1]])){

      seq = p[[1]][d]

      f = get_pos_combn_with_infos(seq, chars, p_name)
      # unlist the list wherever exist in the dataframe and collapse
      # its values with the ":" symbol.
      for(c in 1:nrow(f)){
        if(is.list(f[c,3]))
          f[c,3]=paste(unlist(f[c,3]),collapse=":")
        if(is.list(f[c,4]))
          f[c,4]=paste(unlist(f[c,4]),collapse=":")
        if(is.list(f[c,5]))
          f[c,5]=paste(unlist(f[c,5]),collapse=":")
      }

      fp = na.omit(rbind( f , fp ) )
    }

    i = i + 1
  }

  fp
}


numCores <- detectCores()

results = mcmapply(FUN=combine_all, MoreArgs=list(p_list , chars)  , mc.cores = numCores-1) 

唯一应该运行的是最后一个函数 (combine_all()),将 p_listchars 变量作为输入。

如果这样做,结果是一个 data.frame,其中包含在chars 变量中定义的字符的字符串 (p_list) 内所有可能的位置组合的所有可能组合

我知道这有点复杂,但我不知道如何解释结果。

无论如何。因为我的实际列表 (p_list) 比上面示例中的列表足够大,所以我想让它一次在多个 CPU 内核上以并行模式运行。

为此,您可以看到我使用了parallel 包。我在 linux 机器中运行它(因为据我了解 mcmapply 使用 fork 创建其他进程),但事实是我没有得到任何结果,除了一个空列表。

欢迎任何可能改进算法或使其并行运行的想法。

谢谢。

【问题讨论】:

    标签: r performance parallel-processing combinations


    【解决方案1】:

    这里的问题是你如何使用mapply。如果你不提供任何参数来进行向量化(...),它返回一个长度为 0 的列表是正常的。

    我将使用foreach,因为它更易于使用。你可以看到this guide for parallelism in R with foreach

    那么combine_all就变成了

    combine_all <- function(p_list, chars) {
    
      p_names <- names(p_list)
    
      all_all_f <- foreach(i = seq_along(p_list)) %dopar% {
    
        p <- p_list[[i]][[1]]
        p_name <- p_names[i]
    
        all_f <- foreach(d = seq_along(p)) %do% {
    
          f <- get_pos_combn_with_infos(p[d], chars, p_name)
          # unlist the list wherever exist in the dataframe and collapse
          # its values with the ":" symbol.
          for(c in 1:nrow(f)){
            if(is.list(f[c,3]))
              f[c,3]=paste(unlist(f[c,3]),collapse=":")
            if(is.list(f[c,4]))
              f[c,4]=paste(unlist(f[c,4]),collapse=":")
            if(is.list(f[c,5]))
              f[c,5]=paste(unlist(f[c,5]),collapse=":")
          }
    
          f
        }
    
        do.call("rbind", all_f)
      }
    
      do.call("rbind", all_all_f)
    }
    

    那你就做

    library(foreach)
    doParallel::registerDoParallel(parallel::detectCores() - 1)
    the_res_you_want <- combine_all(p_list = p_list, chars = chars)
    doParallel::stopImplicitCluster()
    

    在 Linux 和 Mac 上,这是注册 fork 集群(mc-like)。在 Windows 上,此代码可能不起作用。

    PS1:请注意,如果您并行处理大量元素,您的数据框可能会非常大。

    PS2:您确实应该将数据框与列列表一起保存,而不是将它们折叠成字符串。见http://r4ds.had.co.nz/many-models.html#list-columns-1

    【讨论】:

    • 要在 Linux / macOS 上模拟 Windows 行为,请使用 doParallel::registerDoParallel(cl &lt;- parallel::makeCluster(2L))。事实上,它会因丢失的对象(“全局”)而窒息。
    • 但是,使用doFuture 后端,在所有平台(Linux、macOS 和 Windows)和所有后端(不仅仅是分叉的)上都可以正常工作。因此,在上面的 Florian 示例中尝试以下操作,它会起作用:library("doFuture"); registerDoFuture(); plan(multiprocess)。对于其他类型的并行后端,请参阅cran.r-project.org/package=future 的主要小插图
    猜你喜欢
    • 1970-01-01
    • 2020-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多