我是Perl和脚本的新手,但我需要一个代码来研究我的。我正在尝试计算存储在multiFASTA文件中的DNA序列中11聚体的频率。通过将我找到的一些脚本合并在一起,我写道:
#!/usr/bin/perl
$k = 11; @bases = ('A','C','G','T');
@words = @bases; open FILE1, ">kmers.txt" or die $!;
for $i (1..$k-1) {
undef @newwords;
foreach $w (@words)
{
foreach $b (@bases)
{
push (@newwords,$w.$b);
}
}
undef @words;
@words = @newwords;
}
foreach $w (@words) {
print FILE1 "$w \n";
}
close FILE1;
my $input=$ARGV[0];
my $output=$ARGV[1];
open(IN,"<$input") || die ("Error opening $input $!");
open OUT, ">$output" or die $|; my $line = <IN>;
print OUT $line;
while ($line = <IN>) {
chomp $line;
if ($line=~m/^>/) {
print OUT "\n",$line,"\n";
} else {
print OUT $line;
}
}
print OUT "\n";
chomp $seq; chomp $k;
#obtain all distinct kmers open FILE2, ">out.txt" or die $!;
for $line (@lines) {
if ($line=~m/^>/) { next; }
}
foreach($i=1; length($line) >= $k; $i++) {
$line =~ m/(^.{$k})/;
$w{$1}{cnt}++;
push @{$w{$1}{pos}}, $i;
$line= substr($seq, 1, length($line)-1);
foreach $line (keys %kmers) {
print FILE2 "$kmers\n";
}
close FILE2;
close OUT;
}
基本上,它读取文件,将所有序列行放在一行中的单独文件中,写下所有11个文件并创建一个“out.txt”文件,我希望他在其中存储11-序列标题mer频率。这是困难的部分(对我来说):如何告诉脚本为每个序列写入序列标题以及11mer频率?
答案 0 :(得分:0)
经过一些修改代码后,我制作了这个:
use strict;
use warnings;
my $in_file = $ARGV[0];
my $out_tvir = $ARGV[1];
my $k = $ARGV[2];
my %seq_hash; # key = seq_name, value = seq;
{
# redefine the record separator
local $/ = ">";
open IN, "<$in_file";
my $in_line = <IN>; # toss the first record
while ( $in_line = <IN> ) {
chomp $in_line; # remove the ">" character in the end
my ( $seq_name, $seq ) = split( /\n/, $in_line, 2 );
$seq =~ tr/ \t\n\r//d; # Remove whitespace
$seq_hash{$seq_name} = uc $seq;
}
close IN;
}
open OUT, ">$out_file";
open OUT2, ">$out_tvir";
foreach my $seq_name ( sort keys %seq_hash ) {
chomp $k;
%kmers = ();
while (length($seq_hash{$seq_name}) >= $k)
{
$seq_hash{$seq_name}=~ m/(^.{$k})/;
$kmers{$1}++;
$seq_hash{$seq_name}= substr($seq_hash{$seq_name}, 1, length($seq_hash{$seq_name})-1);
}
$num_kmers = keys %kmers;
$px=();
$logpx=();
my $H=();
foreach $str (keys %kmers)
{
my $px=$kmers{$str}/$num_kmers;
$logpx=log($px);
$H -= $px * log($px);
if ($H <= 18) {print OUT2 ">$seq_name\t$H\n";}
}
}
close OUT;
...哪种工作,如果我省略了最后一个“if($ H ...”部分,只是让脚本通过列出与每个序列相关的所有H值来完成工作。我无法想象但是,为什么会这样。
答案 1 :(得分:0)
user2029917,您对未声明的变量有一些问题,这会阻止脚本在use strict;
打开的情况下运行;我做了一些修改并稍微清理了一下。
#!/usr/bin/perl
use strict;
use warnings;
my $in_file = $ARGV[0];
my $out_tvir = $ARGV[1];
my $k = $ARGV[2];
my %seq_hash; # key = seq_name, value = seq;
{
# redefine the record separator
local $/ = ">";
open IN, "<", $in_file or die "Can't open ${in_file}: $!";
my $in_line = <IN>; # toss the first record
while ( $in_line = <IN> ) {
chomp $in_line; # remove the ">" character in the end
my ( $seq_name, $seq ) = split( /\n/, $in_line, 2 );
$seq =~ tr/\t\n\r//d; # Remove whitespace
$seq_hash{$seq_name} = uc $seq;
}
close IN;
}
open OUT, ">", $out_tvir or die "Can't open ${out_tvir}: $!";
foreach my $seq_name ( sort keys %seq_hash ) {
chomp $k;
my %kmers;
while (length($seq_hash{$seq_name}) >= $k) {
$seq_hash{$seq_name}=~ m/(^.{$k})/;
$kmers{$1}++;
$seq_hash{$seq_name}= substr($seq_hash{$seq_name}, 1, length($seq_hash{$seq_name})-1);
}
my $num_kmers = keys %kmers;
my $px;
my $logpx;
my $H;
foreach my $str (keys %kmers) {
my $px=$kmers{$str}/$num_kmers;
$logpx=log($px);
$H -= $px * log($px);
if ($H <= 18) {print OUT ">$seq_name\t$H\n";}
}
}
close OUT;
exit;
它现在应该运行,但是我不确定这个脚本是否会产生你想要的输出。例如,对于给定的k-mer,它将为其出现的每个FASTA条目打印H'值(无论FASTA条目如何,它都将始终是相同的值,因为它是根据总出现次数和总数计算的。 k-mers)。目前,它没有打印参考k-mer。这可以通过将最后一位更改为print OUT ">$seq_name\t$str\t$H\n";
来修复,但我不确定这是否是您所追求的行为。如果您能提供有关所需输出的更多详细信息,我们可能会提供更多帮助。
答案 2 :(得分:0)
你不需要创建一个中间文件来强制每个序列成为一行,你的循环计数11mers可以更简单,我不明白为什么你要用所有可能的11mer创建kmers.txt,因为你不要用它。另外,还有一些语法错误和未使用的变量。你不需要第三个参数来改编。如果你把它关掉,默认就会结束。
除了这些问题之外,请注意可能存在4 ^ 11个可能的11个,这可能性接近4.2M。你的deflines将是巨大的(取决于你正在分析的序列的长度)。我猜想,除非你在分析重复序列,否则一个典型的基因会超过一千个11mer。您可能会考虑在您的defline中仅包含任意数量的最丰富的11mer(除非您计划以编程方式处理输出 - 但即便如此,长线也可能存在问题)。
你提交的答案有一些额外的意图,不在你的问题中,但暂时搁置一边,这就是我如何编写脚本以在你的序列中包含前5个11mer频率(任意选择5号之间的任何关系)地点)。我不会解决其他人建议你的正确编码练习问题 - 但你应该注意这些建议。
my $input=$ARGV[0];
my $output=$ARGV[1];
my $defline = '';
my $seq = '';
my $topkmers = '';
open(INPUT,$input);
open(OUTPUT,">$output");
select(OUTPUT);
while(<INPUT>)
{
chomp;
if(/^>/)
{
if($seq ne '')
{
$topkmers = getTopKMers($seq,11,5);
print("$defline $topkmers\n$seq\n");
}
$defline = $_;
$seq = '';
}
else
{$seq .= $_}
}
#Take care of the last record
if($seq ne '')
{
$topkmers = getKMers($seq);
print("$defline $topkmers\n$seq\n");
}
close(INPUT);
close(OUTPUT);
sub getTopKMers
{
my $seq = uc($_[0]);
my $size = $_[1];
my $top = $_[2] - 1; #Submit a 0 to get all kmers
my $hash = {};
#Create the abundance hash
for(my $p = 0;$p < (length($seq) - $size);$p++)
{push(@{$hash->{substr($seq,$p,$size)}},$p}
#Sort by abundance
my @sorted = sort {scalar(@{$hash->{$b}}) <=> scalar(@{$hash->{$a}})} keys(%$hash);
#Get the top few most abundant kmers
my @toplist = $top > -1 ? @sorted[0..$top] : @sorted;
#Creates a string like "ATGCATGCCAA[20]=1,2,... CGTAGCTCTAG[18]=6,23,..."
my $str = join(' ',
map {
"$_\[" .
scalar(@{$hash->{$_}}}) .
"]=" .
join(',',@{$hash->{$_}})
} @toplist);
return($str);
}
这可以消除排序并合并几个步骤以提高效率,但是可以说更容易阅读代码。
注意:我没有运行此代码,所以请原谅我忽略的任何错误。