awk compara array com array na linha anterior

awk compara array com array na linha anterior

Gostaria muito de receber sua ajuda. Estou extraindo informações de arquivos de dados que, em alguns casos, têm mais de um terabyte de tamanho.

  • As variáveis ​​em cada linha são separadas por espaços em branco.
  • A quantidade de variáveis ​​em cada linha é fixa para cada arquivo
  • Três colunas à direita sempre números naturais
  • As linhas sempre começam com um array
  • Arrays sempre contêm uma quantidade fixa de elementos por arquivo
  • Matrizes podem conter de 1 a 5 elementos
  • O arquivo de dados de origem está classificado corretamente

O exemplo abaixo compara uma matriz de três elementos com todas as outras matrizes no arquivo ou bloco ao usar paralelo. Se a matriz corresponder, a segunda coluna da direita será adicionada e as linhas serão mescladas. A coluna mais à direita e a coluna -2 são liberadas.

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

Embora o exemplo represente uma matriz de 3 elementos, estou trabalhando com matrizes contendo 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]}'

Como posso dizer ao awk para comparar o array atual com o array anterior na linha anterior, em vez de fazer com que o awk tente combinar cada array com cada array em um arquivo ou pedaço?

Obrigado

Exemplo de arquivo fonte.

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

Responder1

Os dados de entrada fornecidos como URL em um comentário são delimitados por tabulações. Isso significa que podemos analisar seu primeiro campo delimitado por tabulação como uma espécie de "chave" para comparar com outras linhas. Nós fazemosnãotem que se preocupar com as palavras separadas por espaço no primeiro campo, mas pode tratar todo o primeiro campo como uma entidade única.

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 analisa o campo "contagem" (penúltimo campo) em e count, em seguida, usa o primeiro campo como a "chave" para comparar posteriormente com a chave da linha anterior. Este é o primeiro bloco após o BEGINbloco (que apenas define os delimitadores de entrada e saída).

Se a tonalidade for diferente da tonalidade da linha anterior, isso significa que agora estamos olhando para algum outro conjunto de palavras. Produza a chave e a soma da linha anterior e redefina a soma.

Para todas as linhas, aumente a soma pela contagem desta linha e atualize previous(agora terminamos esta linha, então esta linha keyé a próxima previous).

No final, produza as informações da última linha dos dados.

Você executaria isso usando awk -f script.awk inputfile.

Como uma "linha única":

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

informação relacionada