2010-10-14 28 views
11

Tengo un archivo CSV del cual me gustaría extraer algunos datos: para cada valor distinto en una columna, me gustaría calcular la suma de los valores correspondientes en otra columna. Eventualmente, puedo hacerlo en Python, pero creo que podría haber una solución simple usando awk.Awk suma condicional de un archivo CSV

Este podría ser el archivo 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 

me gustaría llegar:

1 1.6 
2 4.5 
3 5.8 
4 -1.0 
5 10.9 

Por ahora, sólo puedo extraer:

a) el valores de la primera columna:

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

y luego sale:

1 
2 
2 
3 
3 
3 
4 
5 

b) y los valores es igual a, por ejemplo, 1.1 en la última columna con:

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

y luego:

1.1 
1.1 

No puedo extraer simultáneamente las columnas que me interesan, lo cual puede ayudarme al final. Aquí es un ejemplo de salida que puede aliviar el cálculo de las sumas (no sé):

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: Gracias a Elenaher, podríamos decir que la entrada es el archivo anterior.

+0

¿Nos puede dar una entrada de ejemplo? – stew

+0

¡Gracias a todos! ¡Eso es genial! – Wok

Respuesta

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

Tan corto, y aún así, ¡funciona! ¡Gracias! – Wok

+3

+1 Definitivamente el más elegante con '' [: \ t] + '! – ThR37

+0

Finalmente he decidido aceptar esta respuesta ya que es realmente más general y podría adaptarse a muchos problemas similares ajustando los separadores o el número de las columnas – Wok

1

Para su última pregunta, puede utilizar split y mostrar simultáneamente las dos columnas:

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

que imprime:

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

Para el resultado completo que puede utilizar:

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 

que imprime:

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

Gracias. No sabía la palabra clave 'split' para' awk'. – Wok

+0

Gracias, su código funciona (aunque tengo que editar la entrada ya que había un espacio faltante que no se maneja). – Wok

4

Supongamos que tiene las dos columnas que mostró anteriormente: 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

Esto funciona muy bien usando la salida de la línea de Elenaher. – Wok

+0

Su respuesta es excelente para responder mi segunda pregunta. Desearía poder votarlo más de una vez. – Wok

2

Así, en el supuesto de que su entrada es el siguiente:

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

entonces esto debe hacer el truco:

$ 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

Funciona muy bien en su entrada, pero la mía es un poco diferente. Aún gracias. – Wok

+0

Ah, lo siento, lo escribí antes de tener el ejemplo, así que tuve que adivinar = \ –

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

Recibo el siguiente mensaje: 'error de sintaxis cerca del token inesperado' /:.*/, '' – Wok

0

Si Perl es una opción :

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

de salida: se utilizan

1 1.6 
2 4.5 
3 5.8 
4 -1 
5 10.9 

Estas opciones de línea de comandos:

  • -n bucle alrededor de cada línea del archivo de entrada
  • -l elimina los saltos de línea antes de la transformación, y añade ellos de vuelta después
  • -a modo autosplit: divide las líneas de entrada en la matriz @F. El valor predeterminado es la división en espacios en blanco.
  • -e ejecutar el código Perl
  • -F modificador autosplit, en este caso se divide en un color o de un o-más espacio en blanco

@F es la matriz de palabras en cada línea, indexados comenzando con $F[0]
$F[-1] es la última palabra
resultado tienda de hash de %h
al final, iterar a través de las claves del hash ordenados
Imprimir cada elemento $_ y el valor hash $h{$_}

Cuestiones relacionadas