Analisando uma tabela de arquivo de texto e agregando informações

Analisando uma tabela de arquivo de texto e agregando informações

Tenho um arquivo de texto longo com as seguintes colunas, delimitadas por espaço:

Id            Pos Ref  Var  Cn   SF:R1   SR  He  Ho NC       
cm|371443199  22  G     A    R   Pass:8   0   1  0  0       
cm|371443199  25  C     A    M   Pass:13  0   0  1  0
cm|371443199  22  G     A    R   Pass:8   0   1  0  0        
cm|367079424  17  C     G    S   Pass:19  0   0  1  0      
cm|371443198  17  G     A    R   Pass:18  0   1  0  0       
cm|367079424  17  G     A    R   Pass:18  0   0  1  0 

Quero gerar uma tabela que liste cada ID exclusivo junto com contagens para:

  • Quantas vezes esse ID ocorreu
  • Quantas dessas linhas estavam passando (coluna 6)
  • Quantos tinham um Hevalor (coluna 8)
  • Quantos tinham um Hovalor (coluna 9)

Nesse caso:

Id            CountId  Countpass   CountHe CountHO
cm|371443199   3        3          2        1
cm|367079424   2        2          0        2

Como posso gerar essa tabela?

Responder1

Uma maneira de perlassumir infileo conteúdo da sua pergunta (os IDs não estarão necessariamente na mesma ordem na saída porque eu uso um hash para salvá-los):

Conteúdo de script.pl:

use strict;
use warnings;

my (%data);

while ( <> ) { 

    ## Omit header.
    next if $. == 1;

    ## Remove last '\n'.
    chomp;

    ## Split line in spaces.
    my @f = split;

    ## If this ID exists, get previously values and add values of this
    ## line to them. Otherwise, begin to count now.
    my @counts = exists $data{ $f[0] } ? @{ $data{ $f[0] } } : (); 
    $counts[0]++;
    $counts[1]++ if substr( $f[5], 0, 4 ) eq q|Pass|;
    $counts[2] += $f[7];
    $counts[3] += $f[8];
    splice @{ $data{ $f[0] } }, 0, @{ $data{ $f[0] } }, @counts; 
}

## Format output.
my $print_format = qq|%-15s %-10s %-12s %-10s %-10s\n|;

## Print header.
printf $print_format, qw|Id CountId CountPass CountHe CountHo|;

## For every ID saved in the hash print acumulated values.
for my $id ( keys %data ) { 
    printf $print_format, $id, @{ $data{ $id } };
}

Execute como:

perl script.pl infile

Com a seguinte saída:

Id              CountId    CountPass    CountHe    CountHo   
cm|371443198    1          1            1          0         
cm|371443199    3          3            2          1         
cm|367079424    2          2            0          2

Responder2

Aqui está uma solução awkque usa 4 arrays para contar as 4 informações que você precisa. A saída de awké então alimentada, columnalinhando bem as colunas. (Observe que isso também poderia ter sido feito awkusando printf.)

awk 'NR>1 {
    id[$1]++
    if($6 ~ /Pass/) pass[$1]++
    if($8 ~ /1/) he[$1]++
    if($9 ~ /1/) ho[$1]++
} 
END {
   print "Id CountId Countpass CountHe CountHO"
   for(i in id)
      print i" "id[i]" "(pass[i]?pass[i]:0)" "(he[i]?he[i]:0)" "(ho[i]?ho[i]:0)
}' input.txt | column -t

Saída:

Id            CountId  Countpass  CountHe  CountHO
cm|371443198  1        1          1        0
cm|371443199  3        3          2        1
cm|367079424  2        2          0        2

informação relacionada