在给定排列中查找断点

Find breakpoints in given permutation

我正在为生物信息学作业进行文本处理,我们必须通过增加 (+) 或减少 (-) 来分隔数字序列。

A 断点 是序列从 + 切换到 - 或相反的地方。但是,序列中的所有数字都必须按顺序排列。一个序列可以由一个数字组成。

换句话说,增加的条带看起来像:

vector<-c("+1 +2 +3 +4 +5")  
vector<-c("+333 +334")    

但不是:

vector<-c("+1 +3 +4")
vector<-c("+333 +332")

相同的逻辑适用于递减条带。

vector->c("-10 -9 -8")    NOT vector->("-10 -8 -7")

对于以下示例,有 8 个断点:

vector<-c("+3 +4 +5 -12 -8 -7 -6 +1 +2 +10 +9 -11 +13 +14")

#break1: +3 +4 +5
#break2: -12
#break3: -8 -7 -6
#break4: +1 +2 
#break5: +10
#break6: +9
#break7: -11
#break8: +13 +14

有没有办法在 R 中对此进行编码?我之前尝试使用:

vector<-c(3,4,5,12,8,7,6,1,2,10,9,11,13,14)
Strip<- vector[-1] - head(vector, -1)
table(Strip)


#-5 -4 -1  1  2  7  8 
#1  1  3  4  2  1  1 

根据结果 table,我只有 7 个断点(底行 3+4=7)如果没有 +/- 字符,我只能让这段代码查看向量.出于这个原因,此代码不将 +10 和 +9 视为单独的断点,因为它们的顺序未被考虑在内。只有他们的距离(1)是.

由于优点和缺点似乎都适用于正整数流,我会试试这个:

vec <- "+3 +4 +5 -12 -8 -7 -6 +1 +2 +10 +9 -11 +13 +14"

首先,我们可以用空格将其拆分成单独的字符串:

(splvec <- strsplit(vec, "\s+")[[1]])
#  [1] "+3"  "+4"  "+5"  "-12" "-8"  "-7"  "-6"  "+1"  "+2"  "+10" "+9"  "-11"
# [13] "+13" "+14"

(这可以扩展为 not hard-code [[1]],我暂时把它留作练习。)这很好,但是我们 want/need 整数,以便于比较:

(splvec <- as.integer(strsplit(vec, "\s+")[[1]]))
#  [1]   3   4   5 -12  -8  -7  -6   1   2  10   9 -11  13  14

现在,我们需要根据它们从 "increment by 1" 和其他任何变化的时间对它们进行分组:

cumsum(c(TRUE, diff(splvec) != 1))
#  [1] 1 1 1 2 3 3 3 4 4 5 6 7 8 8

这提供了简单的分组信息,我们将把这些信息输入 split(按组创建 list):

str( split(splvec, cumsum(c(TRUE, diff(splvec) != 1))) )
# List of 8
#  $ 1: int [1:3] 3 4 5
#  $ 2: int -12
#  $ 3: int [1:3] -8 -7 -6
#  $ 4: int [1:2] 1 2
#  $ 5: int 10
#  $ 6: int 9
#  $ 7: int -11
#  $ 8: int [1:2] 13 14

如果你绝对必须像以前一样格式化它(每个 运行 的 pos/neg 整数一个字符串),那么:

str( lapply(split(splvec, cumsum(c(TRUE, diff(splvec) != 1))),
            function(a) paste(sprintf('%+d', a), collapse = ' ')) )
# List of 8
#  $ 1: chr "+3 +4 +5"
#  $ 2: chr "-12"
#  $ 3: chr "-8 -7 -6"
#  $ 4: chr "+1 +2"
#  $ 5: chr "+10"
#  $ 6: chr "+9"
#  $ 7: chr "-11"
#  $ 8: chr "+13 +14"

(为了演示,我把东西一步一步地穿过去了,很容易精简。)

这是提供的解决方案的替代方案:

首先,这是输入v <- c("+3 +4 +5 -12 -8 -7 -6 +1 +2 +10 +9 -11 +13 +14")。然后我开始清除所有数字中的字符串:

zeichen <- unlist(strsplit(gsub("\d", "", v), split = " "))
zeichen
[1] "+" "+" "+" "-" "-" "-" "-" "+" "+" "+" "+" "-" "+" "+"

现在,我们定义一个 mapping 来转换 + to 1; - to -1:

mapping <- function(x){
  if(x == "+"){return(1)}
  if(x == "-"){return(-1)}
}
helper <- vapply(zeichen, mapping, numeric(1))
helper
 +  +  +  -  -  -  -  +  +  +  +  -  +  + 
 1  1  1 -1 -1 -1 -1  1  1  1  1 -1  1  1 

最后,我们考虑helper的区别:

delta <- diff(helper)
delta
 +  +  -  -  -  -  +  +  +  +  -  +  + 
 0  0 -2  0  0  0  2  0  0  0 -2  2  0 

delta == -2 的任何地方都有一个从 +- 的断点,反之亦然 delta == 2

现在,我们还需要考虑由于编号(例如+10;+9)而出现断点的情况:

# we create a vector w which contains the numeric data of v
w <- as.numeric(gsub("^\d", "", v))
delta2 <- diff(w) # wherever delta2 is not 1, there is a breakpoint

这里我们确定断点(的索引):

breakpoints <- sort(union(which(delta != 0), which(delta2 != 1)))
breakpoints
 -  +  -  + 
 3  7 11 12 

最后,可以将不同的数组保存在一个列表中(此时有多种方法可以做到这一点):

# firstly, we want v to be a vector
v <- unlist(strsplit(v, split = " "))
# now we declare our list
mylist <- rep(list(NA), length(breakpoints) + 1)
for(i in 1:(length(breakpoints) + 1)){
  f <- ifelse(i > 1, breakpoints[i-1]+1, 0)
  l <- ifelse(i > length(breakpoints), length(v), breakpoints[i])
  mylist[[i]] <- v[f:l]
}
mylist
[[1]]
[1] "+3" "+4" "+5"

[[2]]
[1] "-12"

[[3]]
[1] "-8" "-7" "-6"

[[4]]
[1] "+1" "+2"

[[5]]
[1] "+10"

[[6]]
[1] "+9"

[[7]]
[1] "-11"

[[8]]
[1] "+13" "+14"

希望对您有所帮助。