2014-09-23 1 views
3

지금 당장 나타나는이 프로그램은 .fasta 파일 (유전자 코드가 포함 된 파일)을 가져 와서 데이터로 해시 테이블을 만들고 인쇄하지만, 그것은 아주 느립니다. 문자열을 분할하여 파일의 다른 모든 문자와 비교합니다.펄에서 패턴 인식 속도를 높이려면 어떻게합니까?

use strict; 
use warnings; 
use Data::Dumper; 

my $total = $#ARGV + 1; 
my $row; 
my $compare; 
my %hash; 
my $unique = 0; 
open(my $f1, '<:encoding(UTF-8)', $ARGV[0]) or die "Could not open file '$ARGV[0]' $!\n"; 

my $discard = <$f1>; 
while ($row = <$f1>) { 
    chomp $row; 
    $compare .= $row; 
} 
my $size = length($compare); 
close $f1; 
for (my $i = 0; $i < $size - 6; $i++) { 
    my $vs = (substr($compare, $i, 5)); 
    for (my $j = 0; $j < $size - 6; $j++) { 
     foreach my $value (substr($compare, $j, 5)) { 
      if ($value eq $vs) { 
       if (exists $hash{$value}) { 
        $hash{$value} += 1; 
       } else { 
        $hash{$value} = 1; 
       } 
      } 
     } 
    } 
} 
foreach my $val (values %hash) { 
    if ($val == 1) { 
     $unique++; 
    } 
} 

my $OUTFILE; 
open $OUTFILE, ">output.txt" or die "Error opening output.txt: $!\n"; 
print {$OUTFILE} "Number of unique keys: " . $unique . "\n"; 
print {$OUTFILE} Dumper(\%hash); 
close $OUTFILE; 

미리 도움 주셔서 감사합니다.

+3

아마도 http://www.bioperl.org/wiki/Main_Page에는 최적화 된 솔루션이 있습니다. – toolic

+1

샘플 입력 파일이 있습니까? 시간이 오래 걸리는 작업을 해결하기 위해 타이밍 진술을 인쇄 해 보았습니까? –

+0

당신은 또한 당신이 스크립트에서 무엇을하려고하는지 정확하게 설명 할 수 있습니까?스크립트가 실제로 수행해야하는 작업을 확신 할 수 없을 때 최적화하기가 어렵습니다! 감사. –

답변

3

그것은이 스크립트에서 원하는 무슨 설명에서 명확하지 않다,하지만 당신은 5 개 문자 세트를 일치를 찾고 있다면, 당신은 실제로 문자열 일치를 수행 할 필요가 없습니다 : 당신은 그냥 실행할 수 있습니다 전체 시퀀스를 통해 각 5 문자 시퀀스가 ​​몇 번 발생하는지 계산합니다.

use strict; 
use warnings; 
use Data::Dumper; 

my $str; # store the sequence here 
my %hash; 
# slurp in the whole file 
open(IN, '<:encoding(UTF-8)', $ARGV[0]) or die "Could not open file '$ARGV[0]' $!\n"; 
while (<IN>) { 
    chomp; 
    $str .= $_; 
} 
close(IN); 

# not sure if you were deliberately omitting the last two letters of sequence 
# this looks at all the sequence 
my $l_size = length($str) - 4; 
for (my $i = 0; $i < $l_size; $i++) { 
    $hash{ substr($str, $i, 5) }++; 
} 

# grep in a scalar context will count the values. 
my $unique = grep { $_ == 1 } values %hash; 

open OUT, ">output.txt" or die "Error opening output.txt: $!\n"; 
print OUT "Number of unique keys: ". $unique."\n"; 
print OUT Dumper(\%hash); 
close OUT; 
+0

정말 고마워요! 몇 초 안에 전체 파일을 구문 분석했습니다! 나는 펄에 대해 상당히 익숙하지 않다. grep을 사용할 수있는 단서가 없다. 모든 도움을 주셔서 감사합니다 .--) –

+0

문제 없습니다. 그것은하는 것이 아주 재미 있었다! –

2

이미 가지고있는 정보를 삭제하는 것이 도움이 될 수 있습니다.

나는 $j$i에 달려 있다는 것을 알지 못합니다. 실제로 값을 자신과 일치시킵니다. 그래서 나쁜 계산을하고 있습니다. 1이 1의 제곱이기 때문에 1에 대해 작동합니다. 그러나 5 자리 문자열마다 일치하는 문자열을 계산하는 경우 으로 실제 숫자의 제곱을 구합니다. 그러나

# compute it once. 
my $lim = length($compare) - 6; 

for (my $i = 0; $i < $lim; $i++){ 
    my $vs = substr($compare, $i, 5); 

    # count each unique identity *once* 
    # if it's in the table, we've already counted it. 
    next if $hash{ $vs }; 

    $hash{ $vs }++; # we've found it, record it. 

    for (my $j = $i + 1; $j < $lim; $j++) { 
     my $value = substr($compare, $j, 5); 
     $hash{ $value }++ if $value eq $vs; 
    } 
} 

, 그것은 두 번째 루프 에 대한 index을하고 펄의 C 레벨을 수 있도록 이에 대한 개선이 될 수있다 : 당신이 이런 식으로 한 경우에

당신은 실제로 더 나은 결과를 얻을 것이다 너와 너의 어울리는 것을해라. 또한

my $pos = $i; 
    while ($pos > -1) { 
     $pos = index($compare, $vs, ++$pos); 
     $hash{ $vs }++ if $pos > -1; 
    } 

, 당신은 인덱스를 사용하고, 마지막 두 문자를 생략하고 싶다면 - 당신처럼, 당신이 검색 할 수있는 문자에서 사람들을 제거하는 의미가 있습니다

substr($compare, -2) = '' 

그러나 파일을 반복 할 때 모두을 한 번에 수행 할 수 있습니다. 아래의 코드 은 거의 동일한 코드라고 생각합니다.

my $last_4 = ''; 
my $last_row = ''; 
my $discard = <$f1>; 

# each row in the file after the first... 
while ($row = <$f1>) { 
    chomp $row; 
    $last_row = $row; 
    $row  = $last_4 . $row; 
    my $lim = length($row) - 5; 
    for (my $i = 0; $i < $lim; $i++) { 
     $hash{ substr($row, $i, 5) }++; 
    } 
    # four is the maximum we can copy over to the new row and not 
    # double count a strand of characters at the end. 
    $last_4 = substr($row, -4); 
} 

# I'm not sure what you're getting by omitting the last two characters of 
# the last row, but this would replicate it 
foreach my $bad_key (map { substr($last_row, $_) } (-5, -6)) { 
    --$hash{ $bad_key }; 
    delete $hash{ $bad_key } if $hash{ $bad_key } < 1; 
} 

# grep in a scalar context will count the values. 
$unique = grep { $_ == 1 } values %hash; 
+0

에서 다운로드 할 수 있습니다. 샘플 데이터로 실행 했습니까? 그것은 단지'인자 "caggaccatttctgtatgtaagacaattctatccagcccgccacctctgg의 줄에있는 오류를 fasta.pl 라인 74, 라인 65에 추가로 (+) 표시하지 않습니다.' –

+0

고맙습니다. 불필요한 for 루프를 놓쳤다! –

+0

@anon 시퀀스에 5 개의 뉴클레오타이드 세트가 얼마나 자주 생성되는지 빈도 테이블을 만들려고하십니까? 그렇다면 속도를 이보다 더 높일 수 있습니다. –

0

5 개 개의 문자의 모든 서브 시퀀스를 찾기 위해 글로벌 정규식 일치를 사용하는 코드의이보다 간결 버전에 관심이있을 수 있습니다. 또한 한 번에 전체 입력 파일을 읽고 나중에 그 개행을 제거합니다.

입력 파일의 경로는 명령 라인 파라미터로 예상되고, 출력 STDIN로 전송되고,이

perl subseq5.pl input.txt > output.txt 

I 같은 명령 행의 파일로 리디렉션 될 수있다 나는 또한 그것이 매우 우수하다고 믿기 때문에 Data::Dumper 대신 Data::Dump을 사용했습니다. 그러나 그것은 핵심 모듈이 아니므로 설치해야 할 수도 있습니다.

use strict; 
use warnings; 
use open qw/ :std :encoding(utf-8) /; 

use Data::Dump; 

my $str = do { local $/; <>; }; 
$str =~ tr|$/||d; 

my %dups; 
++$dups{$1} while $str =~ /(?=(.{5}))/g; 

my $unique = grep $_ == 1, values %dups; 

print "Number of unique keys: $unique\n"; 

dd \%dups; 
관련 문제