从基因组数据中获取随机子串

时间:2014-10-25 18:37:15

标签: perl

我正在尝试使用子串函数从fasta格式的基因组中随机获取21个碱基序列。以下是序列的开始:

FILE1数据:

>gi|385195117|emb|HE681097.1| Staphylococcus aureus subsp. aureus HO 5096 0412 complete genome
CGATTAAAGATAGAAATACACGATGCGAGCAATCAAATTTCATAACATCACCATGAGTTTGGTCCGAAGCATGAGTGTTTACAATGTTTGAATACCTTATACAGTTCTTATACATAC

我尝试在阅读我的文件时调整以前的答案,但我没有收到任何错误消息,只是没有输出!该代码有望防止序列有任何重叠,但无论如何,它的可能性非常小。

代码如下:

#!/usr/bin/perl
use strict;
use warnings;
use autodie;

my $outputfile = "/Users/edwardtickle/Documents/randomoutput.txt";

open FILE1, "/Users/edwardtickle/Documents/EMRSA-15.fasta";

open( OUTPUTFILE, ">$outputfile" );

while ( my $line = <FILE1> ) {
    if ( $line =~ /^([ATGCN]+)/ ) {

        my $genome = $1;
        my $size   = 21;
        my $count  = 5;
        my $mark   = 'X';

        if ( 2 * $size * $count - $size - $count >= length($genome) ) {

            my @substrings;
            while ( @substrings < $count ) {
                my $pos = int rand( length($genome) - $size + 1 );
                push @substrings, substr( $genome, $pos, $size, $mark x $size )
                    if substr( $genome, $pos, $size ) !~ /\Q$mark/;
                for my $random (@substrings) {
                    print OUTPUTFILE "random\n";
                }
            }
        }
    }
}

感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

我建议保存数组中子字符串的所有可能位置。这样,您可以在每个子字符串后删除可能性以防止重叠:

#!/usr/bin/perl
use strict;
use warnings;
use autodie;

my $infile  = "/Users/edwardtickle/Documents/EMRSA-15.fasta";
my $outfile = "/Users/edwardtickle/Documents/randomoutput.txt";

my $size       = 21;
my $count      = 5;
my $min_length = ( $count - 1 ) * ( 2 * $size - 1 ) + $size;

#open my $infh,  '<', $infile;
#open my $outfh, '>', $outfile;
my $infh  = \*DATA;
my $outfh = \*STDOUT;

while ( my $line = <$infh> ) {
    next unless $line =~ /^([ATGCN]+)/;

    my $genome = $1;

    # Need a long enough sequence for multiple substrings with no overlap
    if ( $min_length > length $genome ) {
        warn "Line $., Genome too small:  Must be $min_length, not ", length($genome), "\n";
        next;
    }

    # Save all possible positions for substrings in an array.  This enables us
    # to remove possibilities after each substring to prevent overlap.
    my @pos = ( 0 .. length($genome) - 1 - ( $size - 1 ) );

    for ( 1 .. $count ) {
        my $index = int rand @pos;
        my $pos   = $pos[$index];

        # Remove from possible positions
        my $min = $index - ( $size - 1 );
        $min = 0 if $min < 0;
        splice @pos, $min, $size + $index - $min;

        my $substring = substr $genome, $pos, $size;

        print $outfh "$pos - $substring\n";
    }
}

__DATA__
>gi|385195117|emb|HE681097.1| Staphylococcus aureus subsp. aureus HO 5096 0412 complete genome
CGATTAAAGATAGAAATACACGATGCGAGCAATCAAATTTCATAACATCACCATGAGTTTGGTCCGAAGCATGAGTGTTTACAATGTTTGAATACCTTATACAGTTCTTATACATACCGATTAAAGATAGAAATACACGATGCGAGCAATCAAA
CGATTAAAGATAGAAATACACGATGCGAGCAATCAAATTTCATAACATCACCATGAGTTTGGTCCGAAGCATGAGTGTTTACAATGTTTGAATACCTTATACAGTTCTTATACATACCGATTAAAGATAGAAATACACGATGCGAGCAATCAAATTTCATAACATCACCATGAGTTTGGTCCGAAGCATGAGTGTTTACAATGTTTGAATACCTTATACAGTTCTTATACATAC

输出:

Line 2, Genome too small:  Must be 185, not 154
101 - CAGTTCTTATACATACCGATT
70 - ATGAGTGTTTACAATGTTTGA
6 - AAGATAGAAATACACGATGCG
38 - TTCATAACATCACCATGAGTT
182 - GAAGCATGAGTGTTTACAATG

大基因组的替代方法

你在评论中提到基因组的大小可能是2演出。如果情况确实如此,那么可能没有足够的内存来拥有所有可能位置的数组。

在这种情况下,您为每个选定子字符串替换假字符的原始方法将起作用。以下是我将如何使用redo

执行此操作
    for ( 1 .. $count ) {
        my $pos = int rand( length($genome) - ( $size - 1 ) );
        my $str = substr $genome, $pos, $size;

        redo if $str =~ /X/;

        substr $genome, $pos, $size, 'X' x $size;

        print $outfh "$pos - $str\n";
    }

另请注意,如果您的基因组真的那么大,那么您还必须警惕Perl版本的randbits设置:

$ perl -V:randbits
randbits='48';

对于某些Windows版本,randbits设置仅为15,因此只返回32,000个可能的随机值:Why does rand($val) not warn when $val > 2 ** randbits?

答案 1 :(得分:1)

选择随机起点的最佳方法之一是随机播放所有可能起点的列表并选择前几个 - 尽可能多的起点。

使用三参数形式的open词法文件句柄也是最佳做法。

本例中的循环与您自己的循环非常相似 - 使用正则表达式获取基因组。长度$size的子序列可以从零开始到$len_genome - $size,因此程序会生成所有这些起始点的列表,使用List::Util中的效用函数对它们进行混洗,并将它们放入在@start_points

最后,如果有足够的起点来形成$count个不同的子序列,则使用打印语句中的substr打印它们。

use strict;
use warnings;
use autodie;

use List::Util qw/ shuffle /;

my $outputfile = '/Users/edwardtickle/Documents/randomoutput.txt';

open my $in_fh,  '<', '/Users/edwardtickle/Documents/EMRSA-15.fasta';
open my $out_fh, '>', $outputfile;

my $size       = 21;
my $count      = 5;

while (my $line = <$in_fh>) {
   next unless $line =~ /^([ATGCN]+)/;

   my $genome     = $1;
   my $len_genome = length $genome;

   my @start_points = shuffle(0 .. $len_genome-$size);
   next unless @start_points >= $count;
   print substr($genome, $_, 21), "\n" for @start_points[0 .. $count-1];
}

<强>输出

TACACGATGCGAGCAATCAAA
GTTTACAATGTTTGAATACCT
ACATCACCATGAGTTTGGTCC
ATAACATCACCATGAGTTTGG
GGTCCGAAGCATGAGTGTTTA

答案 2 :(得分:0)

我发现将输出for循环移到内部while之外更有效,并向while添加条件,使$genome必须包含{ {1}} - 尚未部分选择的长块。

仅仅因为你有一个长度为117个字符的字符串,并不意味着你会发现5个随机不重叠的字符串。

$size