1

Perl (不是BioPerl)中是否有一种方法可以找到每两个连续字母的数量。

即,AA, AC, AG, AT, CC, CA, ...这样的序列中的数量:

$sequence = 'AACGTACTGACGTACTGGTTGGTACGA'

PS:我们可以手动使用正则表达式,即$GC=($sequence=~s/GC/GC/g),返回序列中GC的个数。

我需要一种自动化和通用的方式。

4

3 回答 3

3

你让我困惑了一段时间,但我认为你想计算给定字符串中的二核苷酸。

代码:

my @dinucs = qw(AA AC AG CC CA CG);
my %count;
my $sequence = 'AACGTACTGACGTACTGGTTGGTACGA';

for my $dinuc (@dinucs) {
    $count{$dinuc} = ($sequence =~ s/\Q$dinuc\E/$dinuc/g);
}

来自Data::Dumper的输出:

$VAR1 = {
          "AC" => 5,
          "CC" => "",
          "AG" => "",
          "AA" => 1,
          "CG" => 3,
          "CA" => ""
        };
于 2011-11-18T15:19:59.293 回答
3

接近TLP 的答案,但没有替代:

my $sequence = 'AACGTACTGACGTACTGGTTGGTACGA';
my @dinucs = qw(AA AC AG AT CC CG);
my %count = map{$_ => 0}@dinucs;

for my $dinuc (@dinucs) {
    while($sequence=~/$dinuc/g) {
        $count{$dinuc}++;
    }
}

基准:

my $sequence = 'AACGTACTGACGTACTGGTTGGTACGA';
my @dinucs = qw(AA AC AG AT CC CG);
my %count = map{$_ => 0}@dinucs;

my $count = -3;
my $r = cmpthese($count, {
        'match' => sub {
            for my $dinuc (@dinucs) {
               while($sequence=~/$dinuc/g) {
                    $count{$dinuc}++;
               }
            }
        },
        'substitute' => sub {
            for my $dinuc (@dinucs) {
                $count{$dinuc} = ($sequence =~ s/\Q$dinuc\E/$dinuc/g);
            }
         }
});

输出:

              Rate substitute      Match
Substitute 13897/s         --       -11%
Match      15622/s        12%         --
于 2011-11-18T15:40:38.093 回答
1

如果你小心的话,Regex 可以工作,但是有一个使用 substr 的简单解决方案,它会更快、更灵活。

(截至本文发布时,标记为已接受的正则表达式解决方案将无法正确计算重复区域中的二核苷酸,例如“AAAA ...”,其中有许多自然发生的序列。

一旦匹配“AA”,正则表达式搜索将在第三个字符处继续,跳过中间的“AA”二核苷酸。这不会影响其他二核苷酸,因为如果您在一个位置有“AC”,那么您可以保证自然不会在下一个碱基中有它。问题中给出的特定序列不会遇到这个问题,因为没有碱基连续出现 3 次。)

我建议的方法更灵活,它可以计算任意长度的单词;将正则表达式方法扩展到更长的单词很复杂,因为您必须使用正则表达式做更多的体操才能获得准确的计数。

sub substrWise {
    my ($seq, $wordLength) = @_;

    my $cnt = {};

    my $w;
    for my $i (0 .. length($seq) - $wordLength) {
        $w = substr($seq, $i, $wordLength);
        $cnt->{$w}++;
    }

    return $cnt;
}

sub regexWise {
    my ($seq, $dinucs) = @_;

    my $cnt = {};
    for my $d (@$dinucs) {
        if (substr($d, 0,1) eq substr($d, 1,1) ) {
            my $n = substr($d, 0,1);
            $cnt->{$d} = ($seq =~ s/$n(?=$n)/$n/g); # use look-ahead
        } else {
            $cnt->{$d} = ($seq =~ s/$d/$d/g);
        }
    }

    return $cnt;
}


my @dinucs = qw(AA AC AG AT CA CC CG CT GA GC GG GT TA TC TG TT);

my $sequence = 'AACGTACTGACGTACTGGTTGGTACGA';

use Test::More tests => 1;
my $rWise = regexWise($sequence, \@dinucs);
my $sWise = substrWise($sequence, 2);
$sWise->{$_} //= '' for @dinucs; # substrWise will not create keys for words not found
# this seems like desirable behavior IMO,
# but i'm adding '' to show that the counts match
is_deeply($rWise, $sWise, 'verify equivalence');

use Benchmark qw(:all);
cmpthese(100000, {
    'regex' => sub {
        regexWise($sequence, \@dinucs);
    },
    'substr' => sub {
        substrWise($sequence, 2);
    }

输出:

1..1
ok 1 - verify equivalence
          Rate  regex substr
regex  11834/s     --   -85%
substr 76923/s   550%     --

对于较长的序列(10-100 kbase),优势不那么明显,但仍能胜出约 70%。

于 2011-12-15T22:30:08.887 回答