我有一个.bedGraph文件,如下所示:
chr start end score
chr1 3000305 3000306 0.006
chr1 3000306 3000307 0.01
chr1 3000307 3000308 0.014
chr1 3000308 3000309 0.017
chr1 3000309 3000310 0.019
chr1 3000310 3000313 0.021
chr1 3000313 3000314 0.029
chr1 3000314 3000315 0.027
chr1 3000315 3000316 0.02
chr1 3000316 3000317 0.011
我必须编写一个脚本,该脚本将遍历此文件并查找得分> 0.02,获取该分数的 开始 值,然后继续搜索得分<0.02,此时它应该抓住之前的 结束 位置。所以在这种情况下,程序应该从文件的开头遍历,确定第一个得分> 0.02,抓住开始位置= 3000310 获得该得分并继续搜索直到得分低于0.02应该抓住之前的结束位置= 3000316 。在此之后,它应继续在文件中搜索此类块并获取包含得分> 0.02的块的开始和结束位置。同样,它应该不要抓住包含分数> 0.02 的块的所有开始和结束,但只是这个块的第一个开始和结束。
我已经编写了部分代码,但不知道如何继续进行:
open BEDGRAPH, $ARGV[0] or die print $!;
my $thresh=0.5;
my $j=1;
my $i=1;
my @arr = <BEDGRAPH>;
my @tmp;
for $i (0 .. $#arr)
{
my ($chr, $start, $end, $score) = split('\s',$arr[$i]);
if($score>=$thresh)
{
push(@tmp,$chr);
push(@tmp,$start);
$j=$i+1;
my ($chr1, $start1, $end1, $score1) = split('\s',$arr[$j]);
while($score1>=$thresh)
{
$j=$j+1;
}
my ($chr2, $start2, $end2, $score2) = split('\s',$arr[$j-1]);
push(@tmp,$end2);
$i=$j+1;
print @tmp;
}
elsif($score>=$thresh)
{
$i=$i+1;
}
}
close(BEDGRAPH);
在这里,我试图推动所需的开始&amp;在@tmp结束职位并打印出来。
答案 0 :(得分:3)
一些建议让你入门。
首先,为什么要循环浏览文件两次?当您将其读入数组并在处理数组时再次执行此操作。为什么不直接按行读取文件进行处理?
# Use a lexical filehandle and test `open` for failure
my $file = $ARGV[0];
open my $fh, "<", $file or die "Failed to open file '$file': $!";
while (<$fh>) {
my ($chr, $start, $end, $score) = split;
...
请注意,我没有引用带有数组索引的列,而是使用有意义的变量名。
此外,避免像瘟疫一样的魔法数字,并将你的阈值放在变量中。这样,如果它确实从0.02更改为0.5,您只需在代码中的一个位置更新它。变量名对于阅读代码的人来说往往比魔术数更有意义。
my $threshold = 0.02;
在您阅读文件时,需要跟踪一些信息。
start
的价值是多少?end
值是多少?你需要这个,因为你没有发现你在下一行之前已经离开了一个街区。如果您考虑如何获取这些信息,您应该能够弄清楚其余部分。
编辑:完全使用您的最新编辑更改了代码。这应该是一个新问题。
您的更新代码存在直接问题:
open BEDGRAPH, $ARGV[0] or die print $!;
使用词法文件句柄(open my $fh
)而不是typeglobs(open FILE
),它们是全局范围的。
my @arr = <BEDGRAPH>;
您在评论中提到您正在使用非常大的文件,但是您正在使用@array = <$fh>
将它们读入内存。你应该真的使用while (<$fh>) ...
while($score1>=$thresh)
{
$j=$j+1;
}
最后,您永远不会更改循环体中$score
或$thresh
的值,因此它会永远运行。
答案 1 :(得分:2)
我认为您需要对ThisSuitisBlackNot所指出的程序进行更改。我以为我会发布一个可能的解决方案。
更新:如果chr名称可以更改,则此程序可能无法正常工作,需要进行调整。
#!/usr/bin/perl
use strict;
use warnings;
my ($prev_chr, $prev_start, $prev_end);
my $thresh = .02;
while (<DATA>) {
my ($chr, $start, $end, $score) = split;
if ($score >= $thresh) {
$prev_chr //= $chr;
$prev_start //= $start;
$prev_end = $end;
}
else {
if ($prev_chr) {
print "$prev_chr $prev_start $prev_end\n";
($prev_chr, $prev_start, $prev_end) = (undef) x 3;
}
}
}
print "$prev_chr $prev_start $prev_end\n" if $prev_chr;
__DATA__
chr1 3000305 3000306 0.006
chr1 3000306 3000307 0.01
chr1 3000307 3000308 0.014
chr1 3000308 3000309 0.017
chr1 3000309 3000310 0.019
chr1 3000310 3000313 0.021
chr1 3000313 3000314 0.029
chr1 3000314 3000315 0.027
chr1 3000315 3000316 0.02
chr1 3000316 3000317 0.011
答案 2 :(得分:0)
#!/usr/bin/perl
use warnings;
use strict;
open my $fh, '<', 'bedgraph.txt' or die "cant open bedgraph.txt $!";
my $thresh = 0.02;
my @start_pos;
my @end_pos;
my $previous_end;
my $header = <$fh>;
ABOVE:
while (<$fh>){
my ($chr, $start, $end, $score) = split;
if ($score > $thresh){
push @start_pos, $start;
$previous_end = $end;
BELOW:
while (<$fh>){
my ($chr, $start, $end, $score) = split;
if ($score < $thresh){
push @end_pos, $previous;
next ABOVE;
}
$previous = $end;
}
}
}
close $fh;
print "Start positions found: @start_pos\n";
print "End positions found: @end_pos\n";
#Start positions found: 3000310
#End positions found: 3000316
简要说明:
答案 3 :(得分:0)
请考虑以下事项:
use strict;
use warnings;
my $startFound = 0;
my $priorEnd;
while (<>) {
$. > 1 or next; # Get past the header
my ( undef, $start, $end, $score ) = split;
if ( $score > .02 and !$startFound ) {
$startFound = 1;
print "Start: $start\n";
}
if ( $score < .02 and $startFound ) {
$startFound = 0;
print "End : $priorEnd\n";
}
$priorEnd = $end;
}
用法:perl script.pl inFile [>outFile]
最后一个可选参数将输出定向到文件。
此脚本设置一个标志($startFound
)来表示一个块的开头,然后检查低于.02的分数和该标志以找到该块的结束。 var $priorEnd
只保留起始/结束对的最后一个'end'值。
希望这有帮助!