Pregunta

Fondo

Creación de un script para contar la frecuencia de las palabras en un archivo de texto plano. Las secuencias de comandos lleva a cabo los siguientes pasos:

  1. conde la frecuencia de las palabras de un corpus.
  2. Conservar cada palabra en el corpus encuentra en un diccionario.
  3. Crea un archivo separado por comas de las frecuencias.

El script se encuentra en: http://pastebin.com/VAZdeKXs

#!/bin/bash

# Create a tally of all the words in the corpus.
#
echo Creating tally of word frequencies...
sed -e 's/ /\n/g' -e 's/[^a-zA-Z\n]//g' corpus.txt | \
  tr [:upper:] [:lower:] | \
  sort | \
  uniq -c | \
  sort -rn > frequency.txt

echo Creating corpus lexicon...
rm -f corpus-lexicon.txt

for i in $(awk '{if( $2 ) print $2}' frequency.txt); do
  grep -m 1 ^$i\$ dictionary.txt >> corpus-lexicon.txt;
done

echo Creating lexicon...
rm -f lexicon.txt

for i in $(cat corpus-lexicon.txt); do
  egrep -m 1 "^[0-9 ]* $i\$" frequency.txt | \
    awk '{print $2, $1}' | \
    tr ' ' ',' >> lexicon.txt;
done

Problema

Las siguientes líneas continuamente ciclo a través del diccionario para que coincida con las palabras:

for i in $(awk '{if( $2 ) print $2}' frequency.txt); do
  grep -m 1 ^$i\$ dictionary.txt >> corpus-lexicon.txt;
done

Funciona, pero es lento porque está escaneando las palabras que había constatado que elimine las que no están en el diccionario. El código realiza esta tarea mediante el escaneo del diccionario para cada palabra. (El parámetro -m 1 detiene la exploración cuando se encuentra el partido.)

Pregunta

¿Cómo optimizar la secuencia de comandos para que el diccionario no es escaneada de principio a fin para cada una de las palabras? La mayoría de las palabras no estará en el diccionario.

Gracias!

¿Fue útil?

Solución

Puede utilizar grep -f a buscar todas las palabras en un solo pase frequency.txt:

awk '{print $2}' frequency.txt | grep -Fxf dictionary.txt > corpus-lexicon.txt
  • -F para buscar cadenas fijas.
  • -x para que coincida con solamente líneas enteras.
  • -f para leer los patrones de búsqueda de dictionary.txt

De hecho, incluso se podría combinar esto con el segundo bucle y eliminar el archivo corpus-lexicon.txt intermedia. Los dos bucles pueden ser reemplazados por un solo grep:

grep -Fwf dictionary.txt frequency.txt | awk '{print $2 "," $1}'

Tenga en cuenta que he cambiado -x a -w.

Otros consejos

Esto es típicamente una de esas secuencias de comandos que escribiría en Perl para la velocidad. Pero si, como yo, que odio idiomas de sólo escritura programación, puede hacerlo todo en AWK:

awk '
    BEGIN {
        while ((getline < "dictionary.txt") > 0)
            dict[$1] = 1
    }
    ($2 && $2 in dict) { print $2 }
' < frequency.txt > corpus-lexicon.txt

No hay necesidad de que el rm -f corpus-lexicon.txt en esta versión.

El uso de un lenguaje de programación real. Todos los de la aplicación para start ups y análisis de archivos que están matando. Por ejemplo, he aquí un ejemplo que acabo prepararon rápidamente en Python (minimización de líneas de código):

import sys, re
words = re.findall(r'(\w+)',open(sys.argv[1]).read())
counts = {}
for word in words:
  counts[word] = counts.setdefault(word,0) + 1
open(sys.argv[2],'w').write("\n".join([w+','+str(c) for (w,c) in counts.iteritems()]))

Pruebas de un aeropuerto internacional alrededor contra un archivo de texto grande que había sentado (1,4 MB, 80.000 palabras de acuerdo con WC), esto se completa en menos de un segundo (18k palabras únicas) en un viejo PowerMac 5 años.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top