在给定排列中查找断点
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"
希望对您有所帮助。
我正在为生物信息学作业进行文本处理,我们必须通过增加 (+) 或减少 (-) 来分隔数字序列。
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"
希望对您有所帮助。