我正在使用R,我有一个包含4个独特字母(DNA)字符串的数据框。我有兴趣计算这些字符串中出现的某些独特字母组合的时间。其中一种可能的情况是检测我多次看到相同的字母背靠背。
我已经遇到过几种可能的方法来实现这一点,使用正则表达式和像stringr这样的包,但仍有一个问题。
这些方法似乎不会遍历子字符串(逐个字母)并考虑行中的下一个字母作为遵守。这是一个问题,同一个字母的重复次数超过2次。
示例(我想计算时间“CC”,而true_count列是我想要的输出):
sequence stringr_count true_count
ACCTACGT 1 1
CCCCCCCC 4 7
ACCCGCCT 2 3
答案 0 :(得分:4)
我建议使用stringi::stri_count_fixed
,如下所示:
> library(stringi)
> seqs <- data.frame(sequence=c('ACCTACGT', 'CCCCCCCC', 'ACCCGCCT'))
> opts <- stri_opts_fixed(overlap=TRUE)
> seqs$true_count <- stri_count_fixed(str=seqs$sequence, pattern='CC', opts_fixed=opts)
> seqs
sequence true_count
1 ACCTACGT 1
2 CCCCCCCC 7
3 ACCCGCCT 3
使用固定模式stringi
比使用gregexpr
快一个数量级:
library(microbenchmark)
# Answer provided by @user20650 in the comments
f1 <- function(x) sapply(gregexpr('(?=CC)', x, perl=T) , function(i) sum(i>0))
f2 <- function(x) stri_count_fixed(
str=x, pattern='CC',
opts_fixed=stri_opts_fixed(overlap=TRUE))
# Generate random sequences
sequence <- stri_rand_strings(n=10000, length=1000, pattern='[ATGC]')
Microbenchmark结果:
> microbenchmark(f1(sequence), f2(sequence))
Unit: milliseconds
expr min lq mean median uq max neval
f1(sequence) 290.90393 304.87107 329.11392 313.39819 327.9860 437.10229 100
f2(sequence) 20.99733 21.12559 21.39206 21.26017 21.4377 27.68867 100
您还可以查看Biostrings library。根据我的经验,它通常比使用stringi
慢,并且需要一些额外的步骤,但提供了许多用于处理生物序列的有用功能,包括countPattern
:
library(Biostrings)
bsequence <- DNAStringSet(sequence)
f3 <- function(x) vcountPattern('CC', x)
Microbenchmark结果:
> microbenchmark(f2(sequence), f3(bsequence))
Unit: milliseconds
expr min lq mean median uq max neval
f2(sequence) 20.83336 21.11473 21.36759 21.25088 21.45000 23.80708 100
f3(bsequence) 86.95430 89.10023 89.51665 89.37103 89.87699 91.88203 100
只是为了确定:
> identical(f1(seqs$sequence), f2(seqs$sequence), f3(BStringSet(seqs$sequence))
[1] TRUE