3
passende

Ich muss eine Rechtschreibprüfung artigen Betrieb in Python wie folgt durchführen:Schnellste Wörterbuch-like

ich eine große Liste von Wörtern haben (lass es das Lexikon nennen). Ich bekomme jetzt einen Text (nennen wir es das Sample). Ich muss nach jedem Beispielwort im Lexikon suchen. Wenn ich es nicht finden kann, ist dieses Beispielwort ein Fehler.

Kurz gesagt - eine Rechtschreibprüfung mit roher Gewalt. Das lineare Durchsuchen des Lexikons für jedes Abtastwort ist jedoch zwangsläufig langsam. Was ist eine bessere Methode, dies zu tun?

Der komplizierende Faktor ist, dass weder die Probe noch das Lexikon in Englisch ist. Es ist in einer Sprache, die statt 26 Zeichen mehr als 300 - in Unicode gespeichert haben kann.

Ein Vorschlag eines Algorithmus/Datenstruktur/Parallelisierungsmethode wird hilfreich sein. Algorithmen, die eine hohe Geschwindigkeit auf Kosten von weniger als 100% Genauigkeit aufweisen, wären perfekt, da ich keine 100% ige Genauigkeit benötige. Ich kenne Norvigs Algorithmus dafür, aber es scheint spezifisch für Englisch zu sein.

+0

Vielleicht möchten Sie diesen Artikel lesen, wie man einen Rechtschreibkorrektor schreibt, vorausgesetzt, Ihr eventuelles Ziel ist es, falsch geschriebene Wörter zu finden, nicht nur richtig geschriebene: http://norvig.com/spell-correct.html –

Antwort

6

Sie eine Reihe von Unicode-Strings verwenden können:

s = set(u"rabbit", u"lamb", u"calf") 

und verwenden Sie die in Betreiber zu prüfen, ob ein Wort vorkommt:

>>> u"rabbit" in s 
True 
>>> u"wolf" in s 
False 

Dieses Look-up ist im Wesentlichen O (1), also spielt die Größe des Wörterbuchs keine Rolle.

bearbeiten: Hier ist der vollständige Code für eine (case-sensitive) Rechtschreibprüfung (2.6 oder höher):

from io import open 
import re 
with open("dictionary", encoding="utf-8") as f: 
    words = set(line.strip() for line in f) 
with open("document", encoding="utf-8") as f: 
    for w in re.findall(r"\w+", f.read()): 
     if w not in words: 
      print "Misspelled:", w.encode("utf-8") 

(Die print übernimmt das Terminal verwendet UTF-8.)

+3

@Atriya : Nein, Sie haben in Ihrem Post gesagt, dass Sie eine lineare Suche verwenden. Dies wird eine Hash-Suche verwenden. –

+0

Ah, interessant! O (1) bedeutet konstante Zeit, unabhängig von der Größe des Lexikons? Das klingt zu gut um wahr zu sein! Danke, ich werde es versuchen! Übrigens, warum benutzen Leute komplexe Dinge wie "Trie's"? –

+0

@SvenMarnach Ist nicht O (1) der optimistischste No-Hash-Kollisionsfall? Was ist mit der Tatsache, dass er eine riesige Menge von Daten indizieren möchte, die möglicherweise Kollisionen im Hashing Algo verursachen könnten? Nur eine "theoretische" Neugier, aber ich denke nicht, dass dies die Zeit für das Nachschlagen verändern würde. – luke14free

0

Dies ist, wo sets an Ort und Stelle kommen. Erstellen Sie einen Satz aller Wörter in Ihrem Wörterbuch und verwenden Sie dann einen Mitgliedschaftsoperator, um zu überprüfen, ob das Wort im Wörterbuch vorhanden ist oder nicht.

Hier ist ein vereinfachtes Beispiel

>>> dictionary = {'Python','check-like', 'will', 'perform','follows:', 'spelling', 'operation'} 
>>> for word in "I will have to perform a spelling check-like operation in Python as follows:".split(): 
    if word in dictionary: 
     print "Found {0} in the dictionary".format(word) 
    else: 
     print "{0} not present in the dictionary".format(word) 


I not present in the dictionary 
Found will in the dictionary 
have not present in the dictionary 
to not present in the dictionary 
Found perform in the dictionary 
a not present in the dictionary 
Found spelling in the dictionary 
Found check-like in the dictionary 
Found operation in the dictionary 
in not present in the dictionary 
Found Python in the dictionary 
as not present in the dictionary 
Found follows: in the dictionary 
>>> 
0

Die durchschnittliche Zeit Komplexität der Hash-Suche in einem Python-Wörterbuch ist O (1). Sie können daher ein "Wörterbuch ohne Werte" (a.k.a. a set) verwenden

0

Dafür sind Python-Wörterbücher und -Sets gedacht! :) Speichern Sie Ihr Lexikon in einem Wörterbuch, wenn jedes Wort einen Wert hat (z. B. Häufigkeit), oder ein Satz, wenn Sie nur nach Existenz suchen müssen. Sie zu suchen ist O (1), also wird es verdammt schnell sein.

lex = set(('word1', 'word2', .....)) 

for w in words: 
    if w not in lex: 
     print "Error: %s" % w 
1

Verwenden Sie eine Baumstruktur, um die Wörter zu speichern, so dass jeder Pfad von Stamm zu Blatt ein einzelnes Wort darstellt. Wenn Ihr Traversal kein Blatt erreichen kann oder ein Blatt vor dem Ende des Wortes erreicht, haben Sie ein Wort, das nicht in Ihrem Lexikon ist.

Abgesehen von den Vorteilen, die Emil in den Kommentaren erwähnt, beachten Sie auch, dass Sie damit Dinge wie Back-Tracking tun können, um alternative Schreibweisen zu finden.

+1

Dies wird auch als Trie oder Prefix-Baum bezeichnet: https://en.wikipedia.org/wiki/Trie Um zu überprüfen, ob ein Wort im Wörterbuch ist, ist in der Größenordnung von O (n) der Wortlänge, die sein sollte unmöglich zu übertreffen. Hashmaps sollten die gleiche Komplexität aufweisen, aber normalerweise mit größeren konstanten Faktoren. Daher ist dies eine wirklich gute Datenstruktur für das Problem! –

+0

@ EmilVikström Es hat auch eine bessere Speicherleistung und ermöglicht es möglicherweise, mehr Informationen abzuleiten (je nachdem, was das Programm gerade macht). – Marcin

+0

@ EmilVikström: Der Kommentar über die Konstante ist falsch im Kontext von Python. Die hochoptimierten integrierten Mengen- und dict-Datenstrukturen werden jede Python-Implementierung eines Trie mit Leichtigkeit übertreffen. –

1

Versuchen Sie es mit einem Satz, wie jeder Ihnen sagt.Set-Lookups wurden von erfahrenen Programmierern im Python-C-Code optimiert, so dass Sie in Ihrer kleinen Anwendung nicht besser werden können.

Unicode ist kein Problem: Set und Dictionary Keys können Unicode oder englischer Text sein, es spielt keine Rolle. Die einzige Überlegung für Sie könnte die Unicode-Normalisierung sein, da verschiedene diakritische Ordnungen nicht gleichwertig sind. Wenn dies ein Problem für Ihre Sprache ist, würde ich zuerst sicherstellen, dass das Lexikon in normalisierter Form gespeichert wird, und dann jedes Wort normalisieren, bevor Sie es überprüfen. Zum Beispiel unicodedata.normalize('NFC', word)

+0

Nur weil etwas optimiert ist, bedeutet Code nicht, dass es nicht besser gemacht werden kann. Der offensichtlichste Grund ist die Verwendung einer falschen Datenstruktur oder eines falschen Algorithmus. Dies ist ein gutes Beispiel. Es ist selten optimal, eine Dictionary-Datenstruktur zu verwenden (ein Baum - oft rot, schwarz - mit einem vollständigen String auf jedem Knoten zum Vergleich). Das ist ein O (N) Vergleich auf jedem Knoten, mit O (In (M)) Tiefe !. Ich habe viel besser in Python mit handgerollten ternären Bäumen oder tatsächlichen Versuchen getan, wenn die Anzahl der Strings groß wird. – ex0du5

+0

Kein Argument da. Vielleicht haben Pythons Designer wirklich einen Fehler gemacht, oder vielleicht sind Hashes die beste Allround-Lösung, sind aber nicht optimal für diese Domäne. Allerdings ist @atriya mehr oder weniger ein Anfänger (nichts für ungut), also bezweifle ich, dass er viel mehr tun wird, als Lookups zu setzen. Daher mein Rat. – alexis

+0

Danke. Nichts für ungut, aber ich muss den effizientesten Weg finden, es zu tun. Ich fange mit Sets an, aber vielleicht muss ich zu diesen gerollten Ternärbäumen gehen und versuche es später. –

0

Zuerst müssen Sie den Index Ihres Lexikons erstellen. Zum Beispiel können Sie Ihr eigenes Indizierungssystem erstellen, aber besser ist die Verwendung von Volltext-Suchmaschinen Full text search engine Ich kann Apache Lucene oder Sphinx für Sie empfehlen. Es ist sowohl schnell als auch Open Source. Nachdem Sie eine Suche Abfragen von Python an die Suchmaschine senden und Antworten abfangen können.