Como calcular a soma dos dados que possuem o mesmo ID na primeira coluna?

2

Eu quero somar os valores das linhas dos meus dados que possuem o mesmo ID na primeira coluna. Meus dados parecem

data.txt

Id    a    b    c    d    e
1     1    2    3    4    5
1     2    3    4    5    6
1     3    4    5    6    7
2     4    5    6    7    8
2     5    6    7    8    9
2     6    7    8    9    10
3     7    8    9   10    11
3     8    9    10  11    12
3     9    10   11  12    13
3     10   11   12  13    14
4     11   12   13  14    15
4     12   13   14  15    16
5     13   14   15  16    17
5     14   15   16  17    18

Resultados obrigatórios

out.txt

Id    a     b   c   d   e
1     6     9   12  15  18
2     15    18  21  24  27
3     34    38  42  46  50
4     23    25  27  29  31
5     27    29  31  33  35
    
por AiB 03.01.2014 / 10:20

4 respostas

3

Este script GNU awk deve fazer o trabalho:

$ awk 'NR==1 { size=NF;$1=$1;OFS="\t";print;next } 
{ for(i=2;i<=NF;i++) {id[$1]=$1; record[$1,i-1]+=$i} } 
END { PROCINFO["sorted_in"]="@ind_num_asc"
  for(i in id){ printf("%s\t",i);
    for(j=1;j<size;j++) printf("%s\t",record[i,j]);
    printf("\n");
  }
} ' data.txt > out.txt
$ cat out.txt
Id  a   b   c   d   e
1   6   9   12  15  18  
2   15  18  21  24  27  
3   34  38  42  46  50  
4   23  25  27  29  31  
5   27  29  31  33  35

Editar:

Aqui está uma versão que preserva a ordem das linhas originais em vez de classificar os IDs:

$ awk 'NR==1 { size=NF;$1=$1;OFS="\t";print;next }
{ if(o[$1]==0) o[$1]=NR
  for(i=2;i<=NF;i++) {record[$1,i-1]+=$i} }
END { PROCINFO["sorted_in"]="@val_num_asc"
  for(i in o){ printf("%s\t",i)
    for(j=1;j<size;j++) printf("%s\t",record[i,j])
    printf("\n") }
}'
    
por 03.01.2014 / 12:18
1
awk '
    NR==1 {print; n=NF; next} 
    {
        id[$1]=1
        for (i=2; i<=n; i++) 
            sum[$1,i] += $i
    } 
    END {
        m = asorti(id, id_s);   # sort the ids
        for (i=1; i<=m; i++) {
            printf "%d", id_s[i]
            for (j=2; j<=n; j++)
                printf " %d", sum[id_s[i],j]
            print ""
        }
    }
' data.txt | column -t > out.txt

out.txt agora contém

Id  a   b   c   d   e
1   6   9   12  15  18
2   15  18  21  24  27
3   34  38  42  46  50
4   23  25  27  29  31
5   27  29  31  33  35
    
por 03.01.2014 / 14:52
1

Um caminho Perl:

$ perl -ane '
    if($.==1){s/\s+/\t/g; print "$_\n"; @a=@F; shift(@a); }
    else{
         push @vals,$F[0] unless defined($sum{$F[0]});
         for($i=0; $i<=$#a;$i++){
           $sum{$F[0]}{$a[$i]}+=$F[$i+1]; 
         }
    }
    END{
     for $f (@vals){ 
      print "$f\t"; 
      print "$sum{$f}{$_}\t" for @a; 
      print "\n" 
     }
    } ' file 

Uma awk way:

$ awk 'BEGIN{OFS="\t"}
       (NR==1){
         printf "%s%s",$1,OFS; 
         for(i=2;i<=NF;i++){ k[i]=$(i); printf "%s%s",$(i),OFS;} 
         printf "\n"; next;
       }{for(i=2;i<=NF;i++){s[$1][k[i]]+=$(i); names[$1]++;}}
       END{for(i in names){
           printf "%s%s",i,OFS; 
           for(l in s[i]){printf "%s%s", s[i][l],OFS;}
           printf "\n";}
       }' file

Ambos alterarão espaços para tabulações para manter as colunas alinhadas. Sua saída é:

Id  a   b   c   d   e   
1   6   9   12  15  18  
2   15  18  21  24  27  
3   34  38  42  46  50  
4   23  25  27  29  31  
5   27  29  31  33  35  
    
por 03.01.2014 / 12:14
1

Com gnu datamash :

{ head -n 1; datamash -s -g 1 sum 2 sum 3 sum 4 sum 5 sum 6; } <infile

use -W se os campos estiverem separados por mais de um espaço em branco:

{ head -n 1; datamash -Wsg 1 sum 2 sum 3 sum 4 sum 5 sum 6; } <infile
    
por 15.02.2016 / 12:04