2012-07-26 2 views
2

psiblast에서 출력 보고서를 파싱 중입니다. 나는 COG 정렬을 사용하고 일치 (homologues)를위한 유전자 데이터베이스를 검색했다. 내가하고 싶은 한 가지는 유전자가 하나 이상의 COG와 일치 하는지를 찾는 것입니다. 내 부분 스크립트는 아래 있습니다.배열의 해시에 값을 푸시하는 동안 오류가 발생했습니다.

저는 여러 COG에 할당 된 유전자에 대한 모든 COG를 보유하는 배열을 만드는 데 특히 문제가 있습니다.

다음과 같은 오류가 발생합니다. "strict refs"가 parse_POG_reports.pl 26 행, 67 행에서 사용 중일 때 ARRAY ref로 문자열 ("COG0003")을 사용할 수 없습니다. ".

배열의 해시로 요소를 푸시하는 것과 관련된 다른 게시물을 살펴 보았습니다. 하지만 하나의 유전자가 동일한 COG에 대해 2 개의 일치 항목을 가지고있을 때 오류가 발생했을 것으로 생각하고 동일한 COG를 배열에 밀어 넣으려고합니다 (즉, 샘플 입력의 마지막 2 줄). 이게 말이 돼? 그렇다면이 문제를 어떻게 피할 수 있습니까?

use strict; 
use warnings; 

my %maxBits;my %COGhit_count; 
my $Hohits={};my %COGhits; 

my $COG_psi_report=$ARGV[0]; 
open (IN, $COG_psi_report) or die "cannot open $COG_psi_report\n"; 
while (my $line=<IN>){ 
    next if ($line =~/^#/); 
    chomp $line; 
    my @columns = split(/\t/,$line); 
    my $bits=$columns[11]; 
    my $COG=$columns[0]; 
    my $hit=$columns[1]; 
    my $Eval=$columns[10]; 
    next if ($Eval > 0.00001); # threshold for significant hits set by DK 
    $COGhit_count{$hit}++; # count how many COGs each gene is homologous to 
    $COGhits{$hit}=$COG; 
    if ($COGhit_count{$hit}>1) { 
      push @{$COGhits{$hit}}, $COG; # 
    } 
    ## for those that there are multiple hits we need to select top hit ## 
    if (!exists $maxBits{$hit}){ 
      $maxBits{$hit}=$bits; 
    } 
    elsif (exists $maxBits{$hit} && $bits > $maxBits{$hit}){ 
      $maxBits{$hit}=$bits; 
    } 
    $Hohits->{$hit}->{$bits}=$COG; 
} 
close (IN); 

예를 입력 :

당신은 라인 (24)을 제거 할 필요가
POG0002 764184357-stool1_revised_scaffold22981_1_gene47608  23.90 159  112  3  1  156  1  153  2e-06 54.2 
POG0002 764062976-stool2_revised_C999233_1_gene54902 23.63 182  121  5  3  169  2  180  2e-06 53.9 
POG0002 763901136-stool1_revised_scaffold39447_1_gene145241  26.45 155  89  3  3  137  5  154  3e-06 53.9 
POG0002 765701615-stool1_revised_C1349270_1_gene168522 23.53 187  115  5  3  169  2  180  5e-06 53.1 
POG0002 158802708-stool2_revised_C1077267_1_gene26470 22.69 216  158  5  3  213  5  216  5e-06 52.7 
POG0003 160502038-stool1_revised_scaffold47906_2_gene161164  33.00 297  154  6  169  424  334  626  6e-40 157 
POG0003 160502038-stool1_revised_scaffold47906_2_gene161164  16.28 172  128  4  23  192  46  203  1e-06 56.6 
POG0003 158337416-stool1_revised_C1254444_1_gene13533 30.06 346  184  7  133  424  57  398  6e-40 155 
POG0003 158337416-stool1_revised_scaffold29713_1_gene153054  28.61 332  194  8  132  424  272  599  2e-38 152 
POG0003 158337416-stool1_revised_scaffold29713_1_gene153054  24.00 200  131  5  1  193  5  190  9e-11 69.3 
+0

감사 - 난 정말 내가 그렇게 생각하지만 난 이전에 $ COGhits {$ 히트} [0] = $ COG을 시도했다 – user1249760

답변

1

(거꾸로 계산) :

그것에서
$COGhits{$hit}=$COG; 

, 당신은합니다 (스칼라 값으로 $COGhits{$hit}을 설정하는 $COG의 값). 나중에 26 행에서 배열로 밀어 넣으려고 $COGhits{$hit}을 역 참조하려고합니다. 거기에는 스칼라가 있기 때문에 작동하지 않습니다.

if을 삭제하고이 행을 변경하십시오. 이제 $hit이 배열 참조에 저장되므로이 작업을 수행해야합니다. $COGhits

$COGhit_count{$hit}++; # count how many COGs each gene is homologous to 
push @{$COGhits{$hit}}, $COG; 

출력 :

$VAR4 = { 
     '158802708-stool2_revised_C1077267_1_gene26470' => [ 
                  'POG0002' 
                 ], 
     '764062976-stool2_revised_C999233_1_gene54902' => [ 
                  'POG0002' 
                 ], 
     '764184357-stool1_revised_scaffold22981_1_gene47608' => [ 
                   'POG0002' 
                   ], 
     '765701615-stool1_revised_C1349270_1_gene168522' => [ 
                  'POG0002' 
                  ], 
     '763901136-stool1_revised_scaffold39447_1_gene145241' => [ 
                   'POG0002' 
                   ], 
     '160502038-stool1_revised_scaffold47906_2_gene161164' => [ 
                   'POG0003', 
                   'POG0003' 
                   ] 
    }; 

당신은 그러나 스칼라와 배열 심판 모두를 원하는 경우,이 코드를 사용해보십시오. 그래도은 권장하지 않습니다.

$COGhit_count{$hit}++; # count how many COGs each gene is homologous to 
if ($COGhit_count{$hit} == 1) { 
    $COGhits{$hit}=$COG;    # Save as scalar 
} 
elsif ($COGhit_count{$hit} == 2) { # If we've just found the second hit, 
    my $temp = $COGhits{$hit};  # save the first and convert $COGhits{$hit} 
    $COGhits{$hit} = [];    # to an array ref, then push both the old and 
    push @{$COGhits{$hit}}, $temp, $COG; # the new value in it. 
} elsif ($COGhit_count{$hit} > 2) { 
    push @{$COGhits{$hit}}, $COG; # Just push the new value in 
} 

생각 : 당신이 실제로 대체했다는 것을 당신은 아마 처음 $COGhits{$hit}=$COG을 가지고 있지만 push 라인을 추가 누른 후 때때로 하나 개 이상의 값이있을 수있는 것으로 나타났습니다,하지만 당신은 실현되지 않았다 오래된 라인.

0

정확히 무엇을 잘못하고 있는지 알려줍니다.

$COGhits{$hit}=$COG; # <--- scalar 
if ($COGhit_count{$hit}>1) { 
     push @{$COGhits{$hit}}, $COG; # <--- array 
} 

값을 참조가 아닌 유형으로 할당 한 다음 참조 유형으로 자동 갱신하려고 할 수 없습니다. Perl은 후자를 수행 할 것입니다. 그러나 충돌 한 데이터 유형을 이미 해당 위치에 저장 한 경우는 아닙니다.

또한이 기적에 의해 처음으로 작업 한 경우 (이 작업은 수행되지 않음),이 작업을 두 번 이상 실행하면 밀어 넣기로 자동 회전 된 배열이 스칼라가 아닌 - 참조 지정.

내가 뭘하고 있는지 잘 모르겠지만, 첫 번째 줄은 일 것입니다.은 삭제해야합니다. 대신 그 구조의


, 당신은 이제까지 $hit의 값을 $COG 하나 이상의 사양이 될 것입니다 여부를 결정합니다. 있을 수있는 경우 단순히 그 4 줄을 push으로 바꾸는 것이 좋습니다.

이전에 다목적 구조 슬롯을 사용해 왔지만 유지 보수가 많이 어렵습니다. 당신이 그런 짓을하기를 원한다면, 당신은이 작업을 수행 할 수 있습니다

my $ref = \$hashref->{ $key }; # autovivifies slot as simple scalar. 
           # it starts out as undefined. 
if (ref $$ref) {    # ref $ref will always be true 
    push @$$ref, $value; 
} 
else { 
    $$ref = defined($$ref) ? [ $$ref, $value ] : $value; 
} 

하지만 당신은 두 갈래의 논리 당신이 어떤 다른 방법으로 혼합 트리를 액세스 할 때마다 작성해야합니다. 스칼라로 얻을 수있는 성능 절감 효과는 테스트와 브랜칭에 의해 다소 상쇄됩니다.

그래서 더 이상이 작업을 수행하지 않습니다. 나는 관계가 1-1인지 1-n인지 미리 결정한다. 아래의 것과 같은 루틴을 사용하면 이러한 종류의 테이블을보다 쉽게 ​​직접 처리 할 수 ​​있습니다.

sub get_list_from_hash { 
    my ($hash, $key) = @_; 
    my $ref = \$hash->{ $key }; 
    return unless defined($$ref); 
    return ref($$ref) ? @$$ref : $$ref; 
} 

sub store_in_hash { 
    $_[0] = {} unless ref $_[0]; 
    my ($hash, $key, @values) = @_; 
    my @defined = grep {; defined } @values; 
    unless (@defined) { 
     delete $hash->{ $key }; 
     return; 
    } 

    my $ref = \$hash->{ $key }; 
    if (ref $$ref) { 
     push @$$ref, @defined; 
    } 
    elsif (defined $$ref) { 
     $$ref = [ $$ref, @defined ]; 
    } 
    elsif (@values > 1) { 
     @$$ref = @defined; 
    } 
    else { 
     ($$ref) = @defined; 
    } 
} 
+0

을 할 것입니다, 최근까지이 동의 일에 대해 몰랐; 먼저 simbabque에 의해 제안 된대로 24 행을 제거하십시오 (빈 배열 예 : ARRAY (0xaf9b58)). – user1249760

+1

24 행을 제거하는 것은 COG에 대한 히트 매핑이 1-1이 아닌 한 이해가되지 않습니다. 특히'$ COGhit_count {$ hit} '의 값이> 1이 될 것으로 예상되는 경우 할당을 제거하는 것이 좋습니다. 그러나 배열의 첫 번째 요소에 할당하는 것은 의미가 없습니다. – Axeman

+0

물론 매핑에 대해 당신이 맞습니다. 생각하지 않았어. – simbabque

관련 문제