(1) gsubfn gsubfn
语句用它的长度和空格替换^...部分,而strapply
从该字符串中提取数字并将其转换为数值。如果字符输出足够,则可以省略strapply
。
> library(gsubfn)
> xx <- gsubfn("\\^[ACGT]*", ~ sprintf(" %s ", nchar(x) - 1), x)
> strapply(xx, "\\d+", as.numeric)
[[1]]
[1] 16 2 40
(2) 循环遍历长度的集合
假设每个ACGT序列的字符数在mn和mx之间,并且使用gsub在一个循环中将长为i的ACGT序列替换为i。如果可能的长度只有几种,则迭代次数很少,因此速度很快,但如果字符串可能具有许多不同的长度,则将需要更多的循环迭代,速度会变慢。 在下面的示例中,我们假设ACGT序列的长度为2、4或6,但这些可能需要进行调整。该解决方案的一个可能的缺点是需要假设一组可能的序列长度。
x <- "4^CG5^CAGT656"
mn <- 2
mx <- 6
y <- x
for(i in seq(mn, mx, 2)) {
pat <- sprintf("\\^[ACGT]{%d}(\\d)", i)
replacement <- sprintf(" %d \\1", i)
y <- gsub(pat, replacement, y)
}
(3) 循环遍历ACGT序列
这个循环遍历ACGT序列,将其中的一个替换为它的长度,直到没有ACGT序列可以替换。如果ACGT序列数量较少,则迭代次数较少,速度会很快;但如果存在大量ACGT序列,则由于需要进行更多迭代,速度会变慢。
x <- "4^CG5^CAGT656"
y <- x
while(regexpr("^", y, fixed = TRUE) > 0) {
y <- sprintf("%s %d %s", sub("\\^.*", "", y),
nchar(sub("^[0-9 ]+\\^([ACGT]+).*", "\\1", y)),
sub("^[0-9 ]+\\^[ACGT]+", "", y))
}
基准测试
这里是一个基准测试。请注意,在某些解决方案中,我将字符串转换为数字(这当然需要额外的时间),但为了使基准测试可比较,我比较了创建字符串而不进行任何数字转换的速度。
x <- "4^CGT5^CCA656"
library(rbenchmark)
benchmark(order = "relative", replications = 10000,
columns = c("test", "replications", "relative", "elapsed"),
regmatch = {
pat <- "(\\^[ACGT]+)"
x2 <- x
m <- gregexpr(pat, x2)
regmatches(x2, m) <- sapply(regmatches(x2, m), modFun)
x2
},
gsubfn = gsubfn("\\^[ACGT]*", ~ sprintf(" %s ", length(x) - 1), x),
loop.on.len = {
mn <- 2
mx <- 6
y <- x
for(i in seq(mn, mx, 2)) {
pat <- sprintf("\\^[ACGT]{%d}(\\d)", i)
replacement <- sprintf(" %d \\1", i)
y <- gsub(pat, replacement, y)
}
},
loop.on.seq = {
y <- x
while(regexpr("^", y, fixed = TRUE) > 0) {
y <- sprintf("%s %d %s", sub("\\^.*", "", y),
nchar(sub("^[0-9 ]+\\^([ACGT]+).*", "\\1", y)),
sub("^[0-9 ]+\\^[ACGT]+", "", y))
}
}
)
以下是结果。两种循环解决方案在所示输入上最快,但它们的性能将根据需要执行的迭代次数而变化,因此实际数据可能有所不同。loop.on.len解决方案的缺点是ACGT长度必须在假定集合中。Josh的regmatch解决方案不涉及循环且速度快。gsubfn解决方案的优点是仅一行代码且特别直接。
test replications relative elapsed
4 loop.on.seq 10000 1.000 1.93
3 loop.on.len 10000 1.140 2.20
1 regmatch 10000 1.803 3.48
2 gsubfn 10000 7.145 13.79
更新:增加了两种循环解决方案并删除了此前无法处理多个ACGT序列的解决方案(根据评论澄清问题)。还重新进行了基准测试,只包括能够处理多个ACGT序列的解决方案。
更新:删除了一种无法处理多个^…序列的解决方案。它之前已从基准测试中删除,但代码尚未删除。在(1)中改进了解释。