字符串/序列的部分匹配

时间:2013-06-28 14:14:32

标签: perl

在多个序列中查找字符串序列AATGGGTTCCA。但是想要允许N个编辑距离(替换或插入字符串)

所以在长字符串中它可能匹配AATG * C * GTTCCA(替换)或AATGGTTCCA(删除)或AATGGG * T * TTCCA(插入)

处理多个序列时最快的算法是什么。

编辑:因为你可以匹配无限的字符串..让我们假设1个核苷酸插入,删除或替换最多5个位置 BLAST也是一个选项

1 个答案:

答案 0 :(得分:5)

一种可能的策略是预处理您要搜索的子序列,然后在所有序列上应用生成的模式。

预处理将生成具有 N 的最大Levenshtein distance的所有模式。缺点是这需要相当大的空间:长度 s 的字符串将产生 s N + 1 可能的模式。要从可能性中获得正则表达式,您可以$re = join "|", @possibilities。由于此处将使用trie优化,因此生成的正则表达式应该非常快。


获得可能性的示例

因为尺寸可以非常快速地增长,所以这里是获得Levenshtein距离1到AC的所有字符串的示例。我们可以通过

获得所有可能性
my@actg=qw/A C T G/;

sub ld{
    my $distance = shift;
    ($distance and @_) or return [@_];
    my $car = shift;
    my @unchanged   = map [$car, @$_], ld($distance, @_);
    my @inserted    = map { my $ins = $_; map [$ins, $car, @$_], ld($distance-1, @_) } @actg;
    my @substituted = map { my $sub = $_; map [      $sub, @$_], ld($distance-1, @_) } @actg;
    my @deleted     = ld($distance-1, @_);
    return @unchanged, @inserted, @substituted, @deleted;
}

如您所见,此代码尚未优化。这可以通过memoization进行改进,并将常见的ld($distance-1, @_)调用分解出来。它还会产生不必要的副本。

然后我们可以打印出所有独特的可能性,例如

my %uniq;
$uniq{$_} = undef for map {join "", @$_} ld(1, split//, "AC");
my @possibilities = keys %uniq;
say for sort @possibilities;

输出:

A
AA
AAC
AC
ACC
AG
AGC
AT
ATC
C
CAC
CC
GAC
GC
TAC
TC

编辑:优化

我对发布如上所述的低性能代码感到内疚。这是一个优化版本,它更喜欢字符串而不是数组,并使用memoization:

use constant ACTG => qw/A C T G/;
use List::MoreUtils 'uniq';

sub ld2 {
    my ($d, $t) = @_;
    ($d and length $t) or return $t;
    state $cache = {};
    my $loc = $t;
    my $result = $cache->{$loc}[$d] //= do {
        my $c = substr $t, 0, 1, '';
        my @unchanged   = map $c . $_, length $t ? ld2($d, $t) : $t;
        my @changed     = map {
            my $s = $_;
            map {; ($s . $c . $_), ($s . $_),  ($_) } length $t ? ld2($d-1, $t) : $t;
        } ACTG;
        [ uniq @unchanged, @changed ];
    };
    return wantarray ? @$result : $result;
}

像[{1}}一样调用。它运行得更快,应该使用更少的内存。