2017-09-07 4 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) 

유일한 것은 p_listchars 변수를 입력으로주고, 마지막 기능 (combine_all())입니다. 이 작업이 완료되면

, 결과는 내가 조금의 알고 chars 변수

에 정의 된 문자의 문자열 (p_list) 내부에 위치의 모든 가능한 조합의 가능한 모든 조합을 포함하는 data.frame입니다 조금 복잡하지만 결과를 설명하는 다른 방법을 모른다.

어쨌든. 필자의 실제 목록 (p_list)이 위 예제의 것보다 충분히 크기 때문에 한 번에 둘 이상의 CPU 코어에서 병렬 모드로 실행하도록 생각했습니다.

내가 볼 수 있듯이 parallel 패키지를 사용했습니다. 나는 리눅스 박스에서 실행한다. 왜냐하면 mcmapply이 다른 프로세스를 생성하기 위해 fork를 사용한다는 것을 이해했기 때문이다. 그러나 진실은 빈리스트를 제외하고는 아무 결과도 없다는 것이다.

알고리즘을 개선하거나 병렬로 실행하는 것이 좋습니다.

감사합니다.

답변

2

여기서 문제는 mapply을 사용하는 방법입니다. 당신이합니다 (...)를 통해 벡터화 인수를 제공하지 않으면, 길이가 0

의 목록이 작업하기 쉽게 때문에 나는 foreach를 사용을 반환 정상입니다. this guide for parallelism in R with foreach을 볼 수 있습니다.

그런 다음 combine_all이 포크 클러스터 (MC-등) 등록하고,

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) 
} 

그런 다음 리눅스 및 Mac에
library(foreach) 
doParallel::registerDoParallel(parallel::detectCores() - 1) 
the_res_you_want <- combine_all(p_list = p_list, chars = chars) 
doParallel::stopImplicitCluster() 

을하게된다. 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) 및 모든 백엔드에서 동일한 작업을 수행 할 수 있습니다. 1). 그래서, 위의 플로리안의 예제를 사용하여 다음을 시도해보십시오 :'library ("doFuture"); registerDoFuture(); 계획 (다중 프로세스)'. 다른 유형의 병렬 백엔드의 경우 https://cran.r-project.org/package=future의 기본 비 네트를 참조하십시오. – HenrikB