AWK para suavização de dados

3

Eu preciso de ajuda para suavizar alguns dados com o awk olny da coluna 4 e a próxima. Este é um exemplo de dados:

Date;time;Time_ms;A;B;C;D
23.11.2012;15:03:00;41236627696;1;2;2;3
23.11.2012;15:04:00;41236628391;2;3;3;11
23.11.2012;15:06:00;41236629097;1;23;7;15
24.11.2012;15:07:00;41236627696;1;4;5;3
24.11.2012;15:08:00;41236628391;3;12;1;2
24.11.2012;15:09:00;41236629097;2;23;71;15;8
23.11.2012;15:10:00;41236627696;7;1;2;2;3
23.11.2012;15:11:00;41236628391;2;3;12;1;
23.11.2012;15:12:00;41236629097;22;2;7;15

A saída não deve modificar Data, hora, Time_ms e imprimir a média de A com o campo A da linha n anterior e o campo A da linha n depois. O mesmo deve ser feito para a coluna B, C, D ... Por exemplo, se n = 1, a segunda linha será:

23.11.2012;15:04:00;41236628391;(1+2+1)/3;(2+3+23)/3;(2+3+7)/3;(3+11+15)/3

Talvez algo como isso possa ser um ponto de partida

BEGIN { WIDTH=3 }

{       DATA[(++N)%WIDTH]=$0    }

(N>=WIDTH) {
        V=0
        for(X=(N+1); X<=(N+WIDTH); X++)
                V+=DATA[X%WIDTH];

        print V/WIDTH;
}

Fonte

    
por Ludovico 12.02.2013 / 19:06

2 respostas

0

este é o script que eu escrevi depois que eu encontrei este

#!/usr/bin/bash     
awk 'BEGIN { FS=OFS=";"
    RS="\n"}
    {
           gsub(/\n/,"",$0) 
           if (max_nf<NF) 
               max_nf=NF 
           max_nr=NR 
           for(x=1; x<=NF; ++x) 
               vector[NR,x]=$x 
        } 
    END { 
    row=1
        printf vector[row,1] OFS vector[row,2] OFS vector[row,3]
               for(col=4; col<max_nf; ++col) 
                      printf OFS "Average(" vector[row,col] ")";
              printf ORS      

    for(row=2; row<max_nr; ++row) {
        printf vector[row,1] OFS vector[row,2] OFS vector[row,3]
              for(col=4; col<max_nf; ++col) 
                printf OFS (vector[row,col]+vector[row-1,col]+vector[row+1,col])/3 ;
            printf ORS
           } 
        }' File_IN.csv>File_OUT.csv

Este script armazena o arquivo csv em uma matriz bidimensional e, em seguida, imprime a primeira linha. Para a coluna > 4 média de impressão (CABEÇALHO). Da segunda linha até o final do arquivo, imprima a primeira, a segunda e a terceira coluna e a média da coluna > 4. Mesmo se o script python do @gilles funcionar bem, escolhi este script como resposta porque usa o AWK conforme solicitado.

    
por 20.02.2013 / 22:13
3

Para o processamento de dados estatísticos, R é geralmente mais fácil de usar.

É mais fácil ler todos os dados na memória. Awk não é a melhor linguagem para isso (embora certamente seja possível). Aqui está um script rápido de Python.

#!/usr/bin/env python
import sys
n = int(sys.argv[1])     # the smooth parameter n must be passed as the first argument to the script
print sys.stdin.readline()  # print the header line
def split_line(line):  # split line into first 3 fields as string, then list of numbers
    fields = line[:-1].split(";")
    return [";".join(fields[:3])] + map(float, fields[3:7])
rows = map(split_line, sys.stdin.readlines())
def avg(i, j):
    return (rows[i-n][j] + rows[i][j] + rows[i+n][j]) / 3
for i in xrange(n, len(rows) - n):
    print ";".join([rows[i][0]] + [str(avg(i, j-2)) for j in xrange(3, 7)])

Se os seus dados são realmente enormes, aqui está um script que eu acho que faz o que você está pedindo. Ele lê 2 * n + 1 linhas, armazena os valores em prev[2*n] a prev[1] plus $0 e imprime a média da (n + 1) linha.

awk -F ';' -v OFS=';' -v n="${1-1}" '
    function avg(i) { return (prev[2*n, i] + prev[n, i] + $i) / 3; }
    NR == 1 { print; next }         # title line: print and skip the rest
    NR >= 2*n+2 {
        # fourth line on: print the average values from the past 3 lines
        # with the labels from the previous line
        print labels[n], avg(4), avg(5), avg(6), avg(7);
    }
    {
        # shift the saved averages by 1 position
        for (i=4; i<=7; i++) {
            for (k=2*n; k>1; k--) prev[k, i] = prev[k-1, i];
            prev[1, i] = $i;
        }
        # save the labels of this line to print in the next round
        for (k=n; k>1; k--) labels[k] = labels[k-1];
        labels[1] = $1 ";" $2 ";" $3;
    }
'
    
por 13.02.2013 / 00:36

Tags