Frage

Hintergrund

ein Skript Geschaffen, um die Häufigkeit von Wörtern in einer Textdatei zu zählen. Das Skript führt die folgenden Schritte aus:

  1. Zählen Sie die Häufigkeit von Wörtern aus einem Korpus.
  2. Bewahren Sie jedes Wort im Korpus in einem Wörterbuch zu finden.
  3. Erstellen Sie eine durch Kommata getrennte Datei der Frequenzen.

Das Skript ist unter: 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

Problem

Die folgenden Zeilen kontinuierlich Zyklus durch das Wörterbuch Wörter entsprechen:

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

Es funktioniert, aber es ist langsam, da es die Worte, scannt es gefunden jede zu entfernen, die nicht im Wörterbuch enthalten sind. Der Code führt diese Aufgabe durch das Scannen des Wörterbuch für jedes einzelne Wort. (Der -m 1 Parameter stoppt den Scan, wenn die Übereinstimmung gefunden wird.)

Frage

Wie würden Sie das Skript so zu optimieren, dass das Wörterbuch nicht von Anfang bis Ende für jedes einzelnes Wort gescannt wird? Die Mehrzahl der Worte wird nicht im Wörterbuch enthalten sein.

Danke!

War es hilfreich?

Lösung

Sie können grep -f verwenden für alle Wörter in einem Durchgang über frequency.txt zu suchen:

awk '{print $2}' frequency.txt | grep -Fxf dictionary.txt > corpus-lexicon.txt
  • -F für feste Zeichenketten suchen.
  • -x nur ganze Zeilen entsprechen.
  • -f die Suchmuster von dictionary.txt
  • lesen

In der Tat könnte man sogar mit der zweiten Schleife kombiniert diese und die Beseitigung den Zwischenkorpus lexicon.txt Datei. Die beiden für Schleifen können durch einen einzigen grep ersetzt werden:

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

Beachten Sie, dass ich geändert -x zu -w.

Andere Tipps

Dies ist in der Regel eine dieser Skripte, dass Sie in Perl für Geschwindigkeit schreiben würde. Aber wenn, wie ich, Sie write-only hate Sprachen programmieren, können Sie alles in Awk tun:

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

Keine Notwendigkeit für die rm -f corpus-lexicon.txt in dieser Version.

Verwenden Sie eine echte Programmiersprache. Alle von der App starten ups und Datei-Scans Sie töten. Zum Beispiel, hier ist ein Beispiel, das ich peitschte nur in Python (Codezeilen zu minimieren):

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()]))

Testen eines gegen eine große Textdatei Ich hatte sitzen aound (1,4 MB, 80.000 Worte nach WC), Damit ist in weniger als eine Sekunde (18k einzigartige Worte) auf einer 5-jährige powermac.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top