Adicionando valores da coluna que possuem o mesmo ID de dados?

2

Eu quero preparar dados diários uniformes a partir de dados mistos diários e sub-diários, adicionando os valores sub-diários e produzindo dados diários uniformes. Minha entrada de amostra e dados de saída desejados se parecem com abaixo.

Arquivo de entrada:

date            Value
01/01/2000     2
01/01/2000     2
01/02/2000     6
01/03/2000     5
01/03/2000     4

Arquivo de saída necessário:

date          Value
01/01/2000    4 (i.e. 2+2)
01/02/2000    6
01/03/2000    9(i.e 5+4)
    
por AiB 27.08.2013 / 06:06

4 respostas

3

Se as linhas estiverem em ordem cronológica:

awk '
 NR==1{print;next}
 $1!=l && NR>2{print l,n;n=0}
 {n+=$2;l=$1}
 END{if (NR>1) print l,n}' < input.file > output.file

Ou seja, imprima a contagem assim que os primeiros campos sejam diferentes da última linha. Isso significa que não precisamos armazenar todos os dados na memória e esperar até o final para exibi-los como em Barun's ou soluções slm . Isso também significa que a ordem é preservada automaticamente.

    
por 27.08.2013 / 08:01
1

Você pode fazer isso com o AWK e seus arrays associativos:

awk '{ 
    if (NR == 1) { print $0 } 
    else { count[$1] += $2 } 
} 
END { 
    # Sort the items based on the date  
    n = asorti(count, indices)  
    for (i = 1; i <= n; i++) {  
        print indices[i], count[indices[i]]
    }
}' < file_name

O bloco END é executado no final quando todos os registros foram processados.

A classificação da matriz foi copiada de esta postagem .

    
por 27.08.2013 / 07:34
1

Você pode usar o seguinte script awk :

$ awk '
  { a[$1]+=$2 }
  END{ for(val in a) printf("%s %s\n", val, a[val]) }
' <(tail -n +2 sample.txt)

No entanto, a ordem da saída não será mais preservada com essa abordagem. No entanto, desde que os dados estejam em ordem numérica de data, um simples sort no final realinhará a saída.

Exemplo

Supondo dados de amostra.

$ cat sample.txt 
date            Value
01/01/2000     2
01/01/2000     2
01/02/2000     6
01/03/2000     5
01/03/2000     4

O script acima gerará os resultados da seguinte forma:

$ awk '
  { a[$1]+=$2 }
  END{ for(val in a) printf("%s %s\n", val, a[val]) }
' <(tail -n +2 sample.txt)
01/02/2000 6
01/01/2000 4
01/03/2000 9

A execução da saída por meio de sort realinha os dados.

$ awk '
  { a[$1]+=$2 }
  END{ for(val in a) printf("%s %s\n", val, a[val]) }
' <(tail -n +2 sample.txt)|sort
01/01/2000 4
01/02/2000 6
01/03/2000 9

O cabeçalho do arquivo original pode ser adicionado de volta:

$ (head -n 1 sample.txt; awk '{a[$1]+=$2}END{for(val in a) printf("%s %s\n", val, a[val])}' <(tail -n +2 sample.txt)|sort)
date            Value
01/01/2000 4
01/02/2000 6
01/03/2000 9

Você pode desdobrar isso um pouco para facilitar a leitura:

$ (
head -n 1 sample.txt
awk '
  { a[$1]+=$2 }
  END{ for(val in a) printf("%s %s\n", val, a[val]) }
' <(tail -n +2 sample.txt) | sort
)
date            Value
01/01/2000 4
01/02/2000 6
01/03/2000 9

UPDATE # 1

Com base no feedback de @StephaneChazelas nos comentários, simplifiquei um pouco mais o meu exemplo. Foi capaz de eliminar o tail ... movendo-o dentro do bloco awk usando isso, ( NR==1{ next } ). Isso irá pular a primeira linha de sample.txt .

Eu também movi o | sort dentro do bloco END{...} . Isso ainda será sort da saída gerada por awk para realinhar os dados com base nas datas. Como awk agora está chamando /bin/sort , ele é colocado entre aspas duplas.

$ awk '
  NR==1{ print; next }
  { a[$1]+=$2 }
    END{ for(val in a) print val, a[val] | "sort" }
' sample.txt
)
date            Value
01/01/2000 4
01/02/2000 6
01/03/2000 9
    
por 27.08.2013 / 08:05
0

Eu faria isso em Perl:

perl -ane '$.==1 && do{$first=$_; next}; $k{$F[0]}+=$F[1]; END{foreach (keys(%k)){print "$_\t$k{$_}\n"}}' file

01/01/2000  4
01/03/2000  9
01/02/2000  6

Essa abordagem tem a vantagem de não precisar que as linhas sejam classificadas cronologicamente.

    
por 27.08.2013 / 15:13