2010-10-14 10 views
11

Ho un file CSV da cui vorrei estrarre alcune informazioni: per ogni valore distinto in una colonna, vorrei calcolare la somma dei valori corrispondenti in un'altra colonna. Alla fine, potrei farlo in Python, ma credo che ci possa essere una soluzione semplice usando awk.somma condizionale Awk da un file CSV

Questo potrebbe essere il file CSV:

2 1:2010-1-bla:bla 1.6 
2 2:2010-1-bla:bla 1.1 
2 2:2010-1-bla:bla 3.4 
2 3:2010-1-bla:bla -1.3 
2 3:2010-1-bla:bla 6.0 
2 3:2010-1-bla:bla 1.1 
2 4:2010-1-bla:bla -1.0 
2 5:2010-1-bla:bla 10.9 

vorrei ottenere:

1 1.6 
2 4.5 
3 5.8 
4 -1.0 
5 10.9 

Per ora, posso estrarre solo:

a) la valori della prima colonna:

awk -F ' ' '{print $(2)}' MyFile.csv | awk -F ':' '{print $(1)}' 

e quindi ottenere:

1 
2 
2 
3 
3 
3 
4 
5 

b) ei valori pari a, per esempio, 1.1 nell'ultima colonna con:

awk -F ' ' '{print $(NF)}' MyFile.csv | awk '$1 == 1.1'

e quindi ottenere:

1.1 
1.1 

Non riesco a estrarre contemporaneamente le colonne a cui sono interessato, il che può aiutarmi alla fine. Ecco un esempio di output che può facilitare il calcolo delle somme (non lo so):

1 1.6 
2 1.1 
2 3.4 
3 -1.3 
3 6.0 
3 1.1 
4 -1.0 
5 10.9 

Edit: Grazie a Elenaher, potremmo dire l'ingresso è il file di cui sopra.

+0

puoi fornirci un esempio? – stew

+0

Grazie a tutti! È fantastico! – Wok

risposta

12
$ awk -F"[: \t]+" '{a[$2]+=$NF}END{for(i in a) print i,a[i] }' file 
4 -1 
5 10.9 
1 1.6 
2 4.5 
3 5.8 
+0

Così breve, e ancora, Funziona! Grazie! – Wok

+3

+1 Sicuramente il più elegante con "" [: \ t] + '! – ThR37

+0

Ho finalmente deciso di accettare questa risposta poiché è molto più generale e potrebbe adattarsi a molti problemi simili modificando i separatori o il numero delle colonne. – Wok

1

Per la vostra ultima domanda, è possibile utilizzare split e visualizzare simultaneamente le due colonne:

cat filename | awk '{split($2,tab,":"); id = tab[1]; print id " -> " $3;}' 

che le stampe:

1 -> 1.6 
2 -> 1.1 
2 -> 3.4 
3 -> -1.3 
3 -> 6.0 
3 -> 1.1 
4 -> -1.0 
5 -> 10.9 

per il risultato completo è possibile utilizzare:

awk -F, '{ split($1,line," "); split(line[2],tab,":"); id=tab[1]; if (sums[id]=="") {sums[id] = 0;} sums[id]+=line[3];} END {for (i=1;i<=length(sums);i++) print i " -> "sums[i]}' < test 

che stampa:

1 -> 1.6 
2 -> 4.5 
3 -> 5.8 
4 -> -1 
5 -> 10.9 
+0

Grazie. Non conoscevo la parola chiave 'split' per' awk'. – Wok

+0

Grazie, il tuo codice funziona (anche se devo modificare l'input poiché c'era uno spazio mancante che non è gestito quindi). – Wok

4

Si presume che si abbiano le due colonne mostrate in precedenza: 1 1.1

BEGIN { 
    last = ""; 
    sum = 0; 
} 

{ 
    if ($1 != last) { 
     if (last != "") { 
      print last " " sum; 
     } 
     sum = 0; 
     last = $1; 
    } 
    sum = sum + $2 
} 

END { 
    print last " " sum; 
} 
+0

Funziona alla grande usando l'output della linea di Elenaher. – Wok

+0

La tua risposta è ottima per rispondere alla mia seconda domanda. Vorrei poterlo revocare più volte. – Wok

2

Quindi, partendo dal presupposto che il vostro input è simile al seguente:

unique_col, to_sum 
1.3, 1 2 3 
1.3, 5 6 7 
1.4, 2 3 4 

allora questo dovrebbe fare il trucco:

$ awk -F, '{ if (seen[$1] == "") { split($2, to_sum, " "); seen[$1] = 0; for (x in to_sum) seen[$1] += to_sum[x]; }} END { for (x in seen) { if (x != "") { print x " " seen[x]; }}}' < input 
1.3 6 
1.4 9 
+0

Funziona benissimo sul tuo input, ma il mio è un po 'diverso. Grazie ancora. – Wok

+0

Ah, scusa - ho scritto prima dell'esempio, quindi ho dovuto indovinare = \ –

0
{ 
    b=$2;    # assign column 2 to the variable 'b' 
    sub(/:.*/, "", b); # get rid of everything after the first colon in b 
    results[b] += $3  
} 
END { for (result in results)print result " " results[result] } 
+0

Ho ricevuto il seguente messaggio: 'Errore di sintassi vicino a token imprevisto' /:.*/, '' – Wok

0

Se Perl è un'opzione :

perl -F'(\s+|:)' -lane '$h{$F[2]} += $F[-1]; END{print "$_ $h{$_}" for sort keys %h}' file

uscita:

1 1.6 
2 4.5 
3 5.8 
4 -1 
5 10.9 

Queste opzioni della riga di comando vengono utilizzati:

  • -n cappio intorno ad ogni riga del file di input
  • -l rimuove a capo prima della lavorazione, e aggiunge di nuovo in seguito
  • -a modalità autosplit - divide le linee di input nell'array @F. Predefinito per la divisione su spazi vuoti.
  • -e eseguire il codice Perl
  • -F autosplit modificatore, in questo caso si divide in un colore o un o-più spazi

@F è la matrice di parole in ciascuna riga, indicizzato iniziano $F[0]
$F[-1] è l'ultima parola
risultato Conservare in hash %h
alla fine scorrere le chiavi ordinate dell'hash
Stampa ogni elemento $_ e il valore hash $h{$_}