在之前的讨论和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_list
和chars
变量作为输入。
如果这样做,结果是一个data.frame,其中包含p_list
变量中定义的字符串(chars
)内所有可能位置组合的所有可能组合
我知道这有点复杂,但我不知道另一种解释结果的方法。
反正。因为我的实际列表(p_list)比上例中的那个更大,所以我想让它一次以多个CPU内核的并行模式运行。
为此,您可以看到我使用了parallel
包。我在linux框中运行它(因为据我所知mcmapply
使用fork来创建其他进程),但事实是我没有得到任何结果,除了空列表。
欢迎任何想法改进算法或让它并行运行。
谢谢。
答案 0 :(得分: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)
}
然后你做
library(foreach)
doParallel::registerDoParallel(parallel::detectCores() - 1)
the_res_you_want <- combine_all(p_list = p_list, chars = chars)
doParallel::stopImplicitCluster()
在Linux和Mac上,这是注册fork cluster(类似mc)。在Windows上,此代码可能无效。
PS1:请注意,如果对大量元素进行并行化,那么您的数据框可能会非常大。
PS2:您应该将数据框保留在列列表中,而不是将它们折叠成字符串。请参阅http://r4ds.had.co.nz/many-models.html#list-columns-1。