Soma das colunas para linhas contendo um termo específico

2

Gostaria de saber se existe algum comando sed ou awk que possa somar todas as colunas das linhas com um identificador idêntico. Por exemplo, meu arquivo data.txt é apresentado como abaixo, exceto que contém ~ 1800 colunas de dados e ~ 1400 linhas.

ABCD:1234  1.23  0.23  0.83   0
ABCD:1234    0    1.10  0.21   0 
EFGH:5678    0    1.90  0.12  8.21
IJKL:9999    1.22  0    1.84  9.21
IJKL:9999    1.44  0   12.94   0
IJKL:9999    1.32  0   24.12   2.43

E como eu gostaria que fosse depois que o comando fosse assim:

ABCD:1234  1.23  1.33  1.04  0
EFGH:5678    0    1.90  0.12  8.21
IJKL:9999   3.98   0   38.9  11.64

Não tenho certeza se isso é possível com awk ou sed (sou biólogo e ainda estou aprendendo os fundamentos do Unix). Qualquer ajuda seria muito apreciada.

    
por DiscoA 11.07.2016 / 09:22

2 respostas

4

Um script awk que não contém o arquivo de entrada nem toda a tabela de resultados na memória:

FNR == 1   { for(i = 1; i <= NF; i++) a[i] = $i;  next }
$1 == a[1] { for(i = 2; i <= NF; i++) a[i] += $i; next }
{
    printf "%s", a[1]; a[1] = $1;
    for(i = 2; i <= NF; i++) { printf "\t%s", a[i]; a[i] = $i };
    printf "\n";
}
END {
    printf "%s", a[1];
    for(i = 2; i <= NF; i++) printf "\t%s", a[i];
    printf "\n";
}

Para executá-lo:

awk -f script.awk data.txt

Resultados:

ABCD:1234       1.23    1.33    1.04    0
EFGH:5678       0       1.90    0.12    8.21
IJKL:9999       3.98    0       38.9    11.64

Em uma nota lateral: é possível fazer isso com sed . Você não vai fazer isso em breve. Consulte aqui para ter uma ideia do motivo.

    
por 11.07.2016 / 10:13
0

Solução alternativa com perl

$ perl -nale '
if(!$seen{$F[0]}++)
{
    print join "\t", @a if @a;
    @a = @F[0..$#F];
}
else
{
    $a[$_] += $F[$_] foreach(1..$#F);
}
print join "\t", @a if eof;
' data.txt 
ABCD:1234   1.23    1.33    1.04    0
EFGH:5678   0       1.90    0.12    8.21
IJKL:9999   3.98    0       38.9    11.64
  • -a divide a linha de entrada nos espaços e os salva em @F array
  • O primeiro campo da linha é usado como chave para a variável hash %seen , se a chave não for encontrada, imprima o conteúdo da matriz @a desde que não esteja vazia e atribua a matriz com campos da nova linha
  • Se a chave já existir, incremente o conteúdo da matriz (do 2º campo para o final) com o conteúdo correspondente da linha atual
  • Para manipular a última entrada, imprima o conteúdo da matriz @a novamente quando o fim do arquivo for atingido


Para a pergunta duplicada: Adicione todas as colunas separadamente no linux se a primeira coluna tiver as mesmas entradas

$ perl -nale '
if(!$seen{$F[0]}++)
{
    print join "\t", @a if @a;
    @a = @F[0..$#F];
}
else
{
    $a[$_] += $F[$_] foreach(1..$#F);
}
print join "\t", @a if eof;
' filename.txt 
AC1481523   6   6   6   6
AC1481676   6   5   6   8


Solução com a criação de um hash de matrizes e a impressão do hash no final:

$ perl -nale '
if($h{$F[0]})
{
    $h{$F[0]}[$_] += $F[$_] foreach (1..$#F)
}
else
{
    $h{$F[0]} = [@F]
}
END { print join "\t",@{$h{$_}} foreach sort keys %h }
' data.txt
ABCD:1234   1.23    1.33    1.04    0
EFGH:5678   0       1.90    0.12    8.21
IJKL:9999   3.98    0       38.9    11.64
    
por 04.10.2016 / 09:22

Tags