processamento de texto (leitura e computação de dois arquivos) [awk, script]

1

Eu tenho um texto como o seguinte: (palavras, domínios de palavras)

car transport
car machine
bank economy
bank politics
bank parks
God religion
...

Existem numerosas palavras, algumas palavras têm domínios diferentes e outras têm apenas um domínio. Eu tenho outro arquivo, uma enorme matriz (300 dimensões de cada linha) composta de palavras e um vetor para cada assim:

bank 0.9 1.5 3.2 -0.2 0.1 ... 
God 1.0 2.1 -0.5 0.7 ...
rose 0.2 -1.8 ...
... ...

Eu gostaria de ler quantas vezes aparece cada palavra no primeiro arquivo e, de acordo com isso, escolher os números "n" mais altos em cada vetor do segundo arquivo, sabendo a qual campo ele pertence. Algo parecido com isto:

car 2
bank 3
God 1

e passe esses números para

bank 4 3.2
bank 3 1.5
bank 2 0.9
God 3 2.1

A primeira parte em que pensei

gawk 'NR==FNR {a[$1]++;next;} dont know what here?' list matrix

Eu sei que é um pouco complexo, mas qualquer ajuda é apreciada. Talvez outro caminho seja mais fácil?

    
por cloudy_fog 14.10.2016 / 15:10

3 respostas

1

awk '
    NR==FNR{                                #operate matrix file first
        A[$1] = 1                           #array of words
        for(i=2;i<=NF;i++)
            B[$1 OFS i] = $i                #array with indexes [word field_num]
        next
        }
    $1 in A{                                #if word in array A
        max = $1 OFS 2
        for(i in B)
            if(i ~ "^" $1 && B[max] < B[i])
                max = i                     #find maximum in B-array
        print max, B[max]                   #output word + field_num + value
        delete B[max]                       #exclude value from next search 
        }
    }
    ' matrix list

Se a versão do awk permitir um script de matrizes de pseudo-multidimensão pode ser simplificado

awk '
    NR==FNR{                                
        for(i=2;i<=NF;i++)
            A[$1][i] = $i                   
        next
        }
    $1 in A{
        max = 2
        for(i in A[$1])
            if(A[$1][max] < A[$1][i])
                max = i
        print $1, max, A[$1][max]
        delete A[$1][max]
        }
    }
    ' matrix list
    
por 14.10.2016 / 16:14
1

Isso é bem complicado. Gostaria de sugerir a criação de um script awk , a menos que alguém invente um milagre de uma linha.

Dentro do seu arquivo awk :

NR==FNR {

    a[$1]++
    next

} #Your probably know what that does since it's your starting point

# If first field is a key in array a
$1 in a { 
    # Assign the number of occurences of this word in variable n
    n=a[$1]  
    # Initialize this value to + INFINITY  
    k=-log(0)

    # Loop on the number of occurences of the word
    for (i=0; i<n; i++) {
        # Initialize max value and its index at the first value of the vector
        m=$2
        i_m=2

        # Loop on the number of fields in the matrix for that word
        for (j=3; j<NF+1; j++) {

            # Look for the largest value that stays below previous max (if none then k is INFINITY)
            if ($j > m && $j < k) { m=$j; i_m=j }

        }
        # Print the word, the index of its max and its value
        printf $1" "i_m" "m"\n"
        # Store the max to be able to scan for the next biggest number at next iteration
        k=m
    }

}

Para executá-lo:

$ awk -f myScript.awk list matrix

Meu script parece funcionar bem, exceto em um caso: se houver um número igual ou mais ocorrências de uma palavra em list do que há valores em seu vetor em matrix . Esse não parece ser o problema aqui, já que seus vetores são bem grandes. Além disso, a inicialização de k at -log(0) para obter o valor inf é um pouco estranha, mas não consegui descobrir como defini-lo como inf diretamente ( =inf não funciona obviamente). Você provavelmente pode fazer com que ele manipule mais casos (se você tiver o mesmo valor várias vezes em seu vetor, por exemplo ...), mas deixarei isso para você, já que você tem um ponto de partida agora!

    
por 14.10.2016 / 17:13
0

TXR Lisp com awk macro:

(let ((h (hash :equal-based)))
  (awk (:inputs "word-dom-pairs")
    (t (inc [h [f 0] 0])))
  (awk (:inputs "word-vectors")
    (t (whenlet ((count [h [f 0]]))
         (fconv - : r)
         (let* ((n-fn-pairs (zip (rest f) (range 2)))
                (n-fn-sorted [sort n-fn-pairs > first]))
           (each ((p [n-fn-sorted 0..count]))
             (prn [f 0] (second p) (first p))))))))

Executar:

$ txr munge.tl 
bank 4 3.2
bank 3 1.5
bank 2 0.9
God 3 2.1

Dados:

$ cat word-dom-pairs 
car transport
car machine
bank economy
bank politics
bank parks
God religion

$ cat word-vectors 
bank 0.9 1.5 3.2 -0.2 0.1
God 1.0 2.1 -0.5 0.7
rose 0.2 -1.8

Aqui está uma versão do programa rolada em uma única expressão awk :

(awk (:inputs "word-dom-pairs" "word-vectors")
     (:let (h (hash :equal-based)))
     ((= arg 1) (inc [h [f 0] 0]))
     ((= arg 2) (whenlet ((count [h [f 0]]))
                  (fconv - : r)
                  (let* ((n-fn-pairs (zip (rest f) (range 2)))
                         (n-fn-sorted [sort n-fn-pairs > first]))
                    (each ((p [n-fn-sorted 0..count]))
                      (prn [f 0] (second p) (first p)))))))

Os dois :inputs dos awk -s anteriormente separados são mesclados em um. Substituímos os padrões true true t pelos seletores com base em qual entrada está sendo processada, dada pela variável arg . O let que liga a variável da tabela de hash é dobrado em uma cláusula :let da macro awk.

Se removermos a cláusula (:inputs ...) , podemos fornecer os arquivos usando um par de argumentos de linha de comando:

$ txr munge.tl file1 file2

TXR Lisp é uma linguagem dinâmica e segura de tipos, na qual as variáveis precisam ser definidas antes da atribuição ou uso. Variáveis inexistentes e cadeias de lixo não são zero numérico, e cadeias que parecem números iguais não são esses números. É por isso que definimos a existência da tabela hash explicitamente e usamos fconv para converter explicitamente o segundo e os campos subsequentes em números reais ( r ).

    
por 14.10.2016 / 18:39