改进和并行化生成指定字符串字符组合的代码

时间:2017-08-29 09:43:06

标签: r parallel-processing combinations

首先让我试着解释下面的代码在做什么。

从上面的列表中获取包含字符串"1MAKK",并尝试在chars

中查找指定字符位置的可能组合

这是初始构象的一个例子

# Initial list
lst1 = list("P1"=list("1MAKK") )
chars = c("M","K")
classes = c("class.1","class.35")
# Get the P name
p_name = names(lst1[1])
# Get the string sequence
p_seq = unlist(lst1[[1]][1])

classes列表只不过是与chars列表对应的某些标签,仅用于某些命名。

现在主要代码是获取这些变量p_name , p_seq并生成一个数据框,其中包含指定字符的位置组合的所有可能组合。

这是代码:

library(stringr)          # str_locate
library(purrr)            # map2

# Functions
move_one <- function(seq){
  if(grepl("1" , seq))
    seq = paste0(substring(seq,2),1)
  else
    seq
}

# Move the number one from the first to last position
seq = move_one(p_seq)

# Get the positions of each character in the string
pos = unlist( map2( 
  .f=function(a ,p) str_locate_all(p, a) , 
  .x=chars , 
  .y=seq), 
  recursive = F
  )
# Check if there is a letter that didn't exist in the sequence and add zeros at the respective list item
for( x in 1:length(pos)){
  ifelse(is.na(pos[[x]][1]) , pos[[x]] <- rbind(pos[[x]] , c(0,0)) , pos[[x]] <- pos[[x]] )
}

# Calculate all possible combinations and transpose the arrays inside the list
ind1 = pmap( 
  .f = function(x) lapply(1:nrow(pos[[x]]), combn, x=as.list(pos[[x]][,1])), 
  .l = list( 1:length(pos) )  
  )

ind1 = pmap( 
  .f = function(x) lapply(ind1[[x]], t) , 
  .l = list( 1:length(ind1) )
  )

# Add Zero at each first element
z = pmap( 
  .f = function(x) lapply(ind1[[x]][1] , rbind , 0 ) , 
  .l = list( 1:length(ind1) )
  )
# Merge the list with the zeros and the complete one
ind1 = map2(
  .f = function(a,b) {a[1]<-b[1]; a},
  .x = ind1,
  .y = z)
# Create a vector for each letter combination
ind1 = pmap( 
  .f = function (x) unlist( lapply(ind1[[x]], function(i) do.call(paste, c(as.data.frame(i), sep = ':'))) ), 
  .l = list ( 1:length(ind1) )
  )

# Get the position of the class.1
isClass1 = grep("class.1", classes)
# Check if the seq is the first one
isFirst = grepl("1",seq)

# Set only 1 and 0 in the vector of UNIMOD.1 if is the first peptide
ifelse(isFirst , ind1[[isClass1]] <- c("1","0") , ind1[[isClass1]] <- c("0") ) 
# expand.grid for all these vectors inside ind1
ind2 = expand.grid(ind1)

# Apply column names in ind2
colnames(ind2) = classes
# Add a column with the p_name and seq
ind3 = cbind( "p_name"=rep(p_name, nrow(ind2) ) , "seq"=rep( gsub('.{1}$','',seq) , nrow(ind2) )  , ind2 )

该特定输入的结果将是

> ind3
  p_name  seq  class.1  class.35
1     P1 MAKK        1         3
2     P1 MAKK        0         3
3     P1 MAKK        1         4
4     P1 MAKK        0         4
5     P1 MAKK        1         0
6     P1 MAKK        0         0
7     P1 MAKK        1       3:4
8     P1 MAKK        0       3:4

正如您所看到的,我尝试使用lapply,map2,pmap方法而不是for循环,以使其更快,并使其有机会在最终版本中运行多个CPU核心。

所以在这里,我需要你的帮助和意见。

我的实际初始列表中没有一个字符串字符,但它看起来像下面一个,但区别在于有数千个内部列表(Px,其中x = {1,2,3,4,。 。2000}并且每个Px可以有大约一百个序列。

p_list = list( "P1" = list( c("1MAK","ERTD","FTRWDSE" )) , "P2" = list( c("1MERTDF","DFRGRSDFG","DFFF")) )

第一个问题,可能是最容易回答的问题,是如何在这样的列表中运行(应用)上述代码。

其次,如何实现并行计算,并使用其中24个CPU核心的多个CPU核心,以节省一些时间。

P.S:最终的结果可能是将所有单个结果(使用rbind)(如前所示)结合到一个数据框中。

欢迎任何改进,想法或建议。

谢谢。

1 个答案:

答案 0 :(得分:1)

第一部分

这基本上是我用于一个字符串的代码。最后,你得到列列表(这很好,你知道它是什么)。

library(purrr)
x <- "MAKK"
chars <- set_names(c("M", "K"), c("class.1", "class.35"))

get_0_and_all_combn <- function(x) {
  map(seq_along(x), function(i) combn(x, i, simplify = FALSE)) %>%
    unlist(recursive = FALSE) %>%
    c(0L, .)
}
get_0_and_all_combn(3:4)
[[1]]
[1] 0

[[2]]
[1] 3

[[3]]
[1] 4

[[4]]
[1] 3 4

get_pos_combn <- function(x, chars) {
  x.spl <- strsplit(x, "")[[1]] 
  map(chars, function(chr) {
    which(x.spl == chr) %>%
      get_0_and_all_combn()
  }) %>%
    expand.grid()
}
get_pos_combn(x, chars)
  class.1 class.35
1       0        0
2       1        0
3       0        3
4       1        3
5       0        4
6       1        4
7       0     3, 4
8       1     3, 4

get_pos_combn_with_infos <- function(seq, chars, p_name) {
  cbind.data.frame(p_name, seq, get_pos_combn(seq, chars))
}
get_pos_combn_with_infos(x, chars, p_name)
  p_name  seq class.1 class.35
1     P1 MAKK       0        0
2     P1 MAKK       1        0
3     P1 MAKK       0        3
4     P1 MAKK       1        3
5     P1 MAKK       0        4
6     P1 MAKK       1        4
7     P1 MAKK       0     3, 4
8     P1 MAKK       1     3, 4

所以,现在,如果您希望我完成答案,我需要知道与您的完整示例相对应的charsclasses

p_list = list( "P1" = list( c("1MAK","ERTD","FTRWDSE" )) , 
               "P2" = list( c("1MERTDF","DFRGRSDFG","DFFF")) )

另外,您确定要制作长度为1的“P1”和“P2”列表吗?