awk compara una matriz con otra en la línea anterior

awk compara una matriz con otra en la línea anterior

Apreciaría tu ayuda. Estoy extrayendo información de archivos de datos que en algunos casos tienen un tamaño de más de un terabyte.

  • Las variables en cada línea están separadas por espacios en blanco.
  • La cantidad de variables en cada línea es fija para cada archivo.
  • Tres columnas a la derecha siempre números naturales.
  • Las líneas siempre comienzan con una matriz.
  • Las matrices siempre contienen una cantidad fija de elementos por archivo
  • Las matrices pueden contener de 1 a 5 elementos.
  • El archivo de datos de origen está ordenado correctamente

El siguiente ejemplo compara una matriz de tres elementos con cualquier otra matriz en el archivo o fragmento cuando se usa paralelo. Si la matriz coincide, se agrega la segunda columna desde la derecha y las líneas se fusionan. La columna más a la derecha y la columna -2 están vacías.

g@grml # zcat googlebooks-eng-us-all-3gram-20120701-zz.gz | head
Z'Z . _END_     1840    1       1
Z'Z . _END_     1847    1       1
Z'Z . _END_     1850    1       1
Z'Z . _END_     1855    1       1
Z'Z . _END_     1856    1       1
Z'Z . _END_     1857    1       1
Z'Z . _END_     1860    1       1
Z'Z . _END_     1863    1       1
Z'Z . _END_     1865    1       1
Z'Z . _END_     1869    1       1



g@grml # zcat googlebooks-eng-us-all-3gram-20120701-zz.gz | parallel -k -q --pipe awk '{a[$1" "$2" "$3] +=$(NF-1)} END{for (i in a) print i, a[i]}' | head 
Zz_NOUN _NOUN_ , 98
zz _._ _PRT_ 120
ZZ or_CONJ _NOUN_ 122
ZZ_NOUN _DET_ _VERB_ 59
zz_DET _NOUN_ . 86
ZZ is_VERB reached 42
ZZ_NUM ^ ^ 65
ZZ _NOUN_ _VERB_ 3163
ZZ ,_. " 52
ZZ / _NUM_ 275

Aunque el ejemplo muestra una matriz de 3 elementos, estoy trabajando con matrices que contienen de 1 a 5 elementos.

awk '{a[$1] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2" "$3] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2" "$3" "$4] +=$(NF-1)} END{for (i in a) print i, a[i]}'
awk '{a[$1" "$2" "$3" "$3" "$5] +=$(NF-1)} END{for (i in a) print i, a[i]}'

¿Cómo le digo a awk que compare la matriz actual con la matriz anterior en la línea anterior en lugar de que awk intente hacer coincidir cada matriz con cada matriz en un archivo o fragmento?

Gracias

Archivo fuente de ejemplo.

wget --show-progress -cq http://storage.googleapis.com/books/ngrams/books/googlebooks-eng-us-all-3gram-20120701-zz.gz -O - | zcat

Respuesta1

Los datos de entrada proporcionados como URL en un comentario están delimitados por tabulaciones. Esto significa que podemos analizar su primer campo delimitado por tabulaciones como una especie de "clave" para comparar con otras líneas. Hacemosnodebe preocuparse por las palabras separadas por espacios dentro del primer campo, pero puede tratar todo el primer campo como una sola entidad.

BEGIN { OFS = FS = "\t" }

{
    count = $(NF - 1)
    key = $1
}

key != previous {
    if (previous != "")
        print previous, sum

    sum = 0
}

{
    sum += count
    previous = key
}

END {
    if (previous != "")
        print previous, sum
}

Este awkprograma analiza el campo "recuento" (penúltimo campo) y countluego utiliza el primer campo como "clave" para compararlo posteriormente con la clave de la línea anterior. Este es el primer bloque después del BEGINbloque (que simplemente establece delimitadores de entrada y salida).

Si la clave es diferente de la clave de la línea anterior, esto significa que ahora estamos viendo otro conjunto de palabras. Genere la clave y la suma de la línea anterior y restablezca la suma.

Para todas las líneas, incremente la suma por el recuento de esta línea y actualice previous(ahora hemos terminado con esta línea, por lo que esta línea keyes la siguiente previous).

Al final, genere la información de la última línea de los datos.

Ejecutarías esto usando awk -f script.awk inputfile.

Como "una sola línea":

awk -F '\t' 'BEGIN{OFS=FS} {c=$(NF-1);k=$1} k!=p {if(p!="")print p,s;s=0} {s+=c;p=k} END {if(p!="") print p,s}' file

información relacionada