Média de linhas com a mesma primeira coluna

7

Dado um arquivo com duas colunas:

Id  ht
510 69
510 67
510 65
510 62
510 59
601 29
601 26
601 21
601 20

Eu preciso de uma maneira de unir todas as linhas com o mesmo ID em uma que tenha uma altura média. Nesse caso, (69 + 67 + 65 + 62 + 59) / 5 = 64 e (29 + 26 + 21 + 20) / 4 = 24, a saída deve ser:

Id  Avg.ht
 510 64
 601 24

Como posso fazer isso usando sed / awk / perl?

    
por jack 02.10.2012 / 00:10

4 respostas

6

Usando o awk:

O arquivo de entrada

$ cat FILE
Id  ht
510 69
510 67
510 65
510 62
510 59
601 29
601 26
601 21
601 20

Awk em um shell:

$ awk '
    NR>1{
        arr[$1]   += $2
        count[$1] += 1
    }
    END{
        for (a in arr) {
            print "id avg " a " = " arr[a] / count[a]
        }
    }
' FILE

Ou com o Perl em um shell:

$ perl -lane '
    END {
        foreach my $key (keys(%hash)) {
            print "id avg $key = " . $hash{$key} / $count{$key};
        }
    }
    if ($. > 1) {
        $hash{$F[0]}  += $F[1];
        $count{$F[0]} += 1;
    }
' FILE

A saída é:

id avg 601 = 24
id avg 510 = 64.4

E durar pela piada, um perl obscurecido one-liner =)

perl -lane'END{for(keys(%h)){print"$_:".$h{$_}/$c{$_}}}($.>1)&&do{$h{$F[0]}+=$F[1];$c{$F[0]}++}' FILE
    
por 02.10.2012 / 02:01
2
#!/usr/bin/perl
use strict;
use warnings;

my %sum_so_far;
my %count_so_far;
while ( <> ) {
    # Skip lines that don't start with a digit
    next if m/^[^\d]/;

    # Accumulate the sum and the count
    my @line = split();
    $sum_so_far{$line[0]}   += $line[1];
    $count_so_far{$line[0]} += 1;
}

# Dump the output
print "Id Avg.ht\n";
foreach my $id ( keys %count_so_far ) {
    my $avg = $sum_so_far{$id}/$count_so_far{$id};
    print " $id $avg\n";
}

Saída:

ire@localhost$ perl make_average.pl input.txt 
Id Avg.ht
 510 64.4
 601 24

Observe que sua saída de amostra está errada. Não há como você obter uma média de 52 quando todos os valores para esse id forem 59 ou maiores.

Além disso, você tem uma letra l em uma de suas colunas, mascarada como o número 1 ...

    
por 02.10.2012 / 01:05
2

Com gnu datamash :

datamash -H -s -g 1 mean 2 <file
GroupBy(Id) mean()
510 64.4
601 24

Este s orts e g grupos por 1 st campo calculando 2 nd campo mean valor, preservando H eaders. Ele assume que os campos estão separados por uma única guia. Use -W, --whitespace se eles estiverem separados por vários espaços em branco ou -t, --field-separator= para definir outro separador de campo (espaço, vírgula, etc). Como datamash requer entrada classificada, a saída será classificada pela coluna agrupada.

    
por 01.10.2015 / 23:36
1

Veja o que é feito aqui: link

A parte difícil essencial é fazer uma operação 'agrupar por'. O script vinculado faz isso usando um hash.

Nesse link eles estão calculando a soma, mas obter a média não será muito diferente.

    
por 02.10.2012 / 00:40