2017-09-07 6 views
1

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) 

唯一、1は実行する必要がありp_listchars変数を入力として与え、最後の関数(combine_all())です。これが行われた場合

、結果はchars変数

で定義された文字の文字列内の位置のすべての可能な組み合わせのすべての可能な組み合わせが含まれていdata.frame(p_list)である私はそれを少し知っています私は結果を説明する別の方法を知らない。

とにかく。私の実際のリスト(p_list)は上記の例よりも十分に大きいので、一度に複数のCPUコアで並列モードで動作させることを考えました。

このような目的のために、私はparallelパッケージを使用しました。私はLinuxのボックスで実行します(なぜなら、mcmapplyが他のプロセスを作成するためにforkを使うことを理解していたからです)。しかし、真実は空のリストを除いて何の結果も得られなかったことです。

多分アルゴリズムを改善したり、それを並行して実行させることをお勧めします。

ありがとうございます。

答えて

2

ここでは、問題は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) 
} 

次に、あなたは、LinuxおよびMac上で

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

を行うとなり、これはフォーククラスター(MC-など)を登録しています。 Windowsでは、このコードは動作しない可能性があります。

PS1:多くの要素にわたって並列化すると、データフレームがかなり大きくなる可能性があることに注意してください。

PS2:実際には、データフレームを文字列に折りたたむのではなく、列リストで保持する必要があります。 http://r4ds.had.co.nz/many-models.html#list-columns-1を参照してください。

+0

Linux/macOSでWindowsの動作をエミュレートするには、 'doParallel :: registerDoParallel(cl < - parallel :: makeCluster(2L))'を使用します。実際には、欠けているオブジェクト(「グローバル」)で窒息します。 – HenrikB

+0

しかし、[doFuture](https://cran.r-project.org/package=doFuture)バックエンドを使うと、すべてのプラットフォーム(Linux、macOS、Windows)とすべてのバックエンドもの)。だから、上記のFlorianの例で次のように試してみましょう。これはうまくいくでしょう: 'library(" doFuture "); registerDoFuture();計画(マルチプロセス) '。他のタイプの並列バックエンドについては、https://cran.r-project.org/package=futureのメインのバイナリを参照してください。 – HenrikB

関連する問題