Im Web fehlen häufig Angaben darüber, in welcher Sprache eine Seite geschrieben ist. Trotzdem würden wir gerne den Benutzern unseres Dienstes nur diejenigen Inhalte anzeigen, die sie auch verstehen. Auch in anderen Bereichen erhalten wir oft Texte, deren Sprachen wir nicht kennen.
Daher wollen wir ein einfaches System zur Klassifikation einer Sprache in Python entwickeln.
Hierzu versuchen wir, ein n-gram-Modell auf Zeichenebene zu verwenden.
Trainingsdaten
Zum Trainieren des Modells verwende ich die Google-1-gram-Daten. Besser wären zwar die Google-2gram-Date, da hier Berechnungen über Wortgrenzen möglich sind, doch der 2gram-Datensatz ist erheblich größer.
Die einzelnen Dateien speichere ich nach Sprachen getrennt in folgender Ordnerstruktur:
languages/
english/
french/
german/
...
Hat man die kompletten 1gram-Daten mehrerer Sprachen heruntergeladen, muss man sie noch entpacken. Dies erledigt man am besten automatisiert mit einem Shellskript:
Modellbildung
Zunächst benötigen wir eine Funktion, die uns die Buchstaben-n-Gramme aus den Google-Daten extrahiert. Lasst euch im Folgenden nicht von den Google-1grams (bezogen auf Wortanzahl) und den Buchstaben-ngrams (bezogen auf Zeichenanzahl) verwirren.
Mit folgender Funktion können wir aus einer Zeichenkette alle Buchstaben-ngrams extrahieren:
Die Vorkommen jedes n-Grams zählen wir mithilfe eines Dictionaries. In einem ersten Schritt berechnen wir dazu für jede Datei die n-Gram-Verteilung. Damit dies schneller geht, setzen wir Parallelisierung über concurrent.futures.ThreadPoolExecutor ein. Die Ausgabe wird in gleiche Dateien in einem Ordner model geschrieben.
Haben wir diese Teilmodelle pro Datei ausgelesen, müssen wir noch alle Dateien einer Sprache zu einem kompletten Sprachmodell kombinieren. Hierzu schreiben wir eine weitere Datei, die die Teilmodelle alle einliest und gemäß der Gesamtanzahl der enthaltenen n-Grams anteilig auf das Gesamtmodell aufaddiert. Das Ergebnis wird in einen Ordner finished_models geschrieben.
Detektion
Hat man alle Modelle generiert, kann man durch einen Vergleich der n-Gram-Verteilung des Referenztexts mit allen Modellen berechnen, welche sich am ähnlichsten sind. Ich habe hierzu den Mittleren-Quadratischen-Fehler verwendet, es gäbe jedoch auch statistische Tests für Wahrscheinlichkeitsverteilungen. Jedoch schien mir der Chi-Quadrat-Test, der für diskrete Verteilungen empfohlen wurde, einen Fehler von Unendlich zu ergeben, wenn im erwarteten Wertebereich (also in unserem Sprachmodell) ein Verteilungswert 0 ist. Wahrscheinlich könnte man diesen Fall vernachlässigen, da unsere Modelle auf sehr vielen Daten trainiert wurden, jedoch schien mir diese Situation dennoch seltsam.
Der Referenztext wird dann über die stdin eingelesen.
In Dictionary errors sind dann die Fehler für alle Sprachen gespeichert. Die Sprache mit minimalem Fehler ist die vermutete Sprache des Referenztexts.
I do not maintain a comments section. If you have any questions
or comments regarding my posts, please do not hesitate to send me
an e-mail to blog@stefan-koch.name.