Ich habe zwei große Dateien mit Absätzen englischen Textes:
- Der erste Text ist ungefähr 200 Seiten lang und hat ungefähr 10 Absätze pro Seite (jeder Absatz ist 5 Sätze lang).
- Der zweite Text enthält fast genau die gleichen Absätze und Texte wie der erste. Es ist auch 200 Seiten lang mit 10 Absätzen pro Seite. Die Absätze sind jedoch zufällig und in einer anderen Reihenfolge als der erste Text. Außerdem weist ein großer Prozentsatz der Absätze im Vergleich zu ähnlichen Absätzen geringfügige Wortlautänderungen auf. Zum Beispiel könnte ein Absatz im ersten Text einen Satz haben, wie
Like Jimmy, I wanted to go to the palace
der entsprechende Satz im Absatz des zweiten Textes lauten würdeLike Jimmy, I really wanted to go to the castle
.
Ich möchte in der Lage sein, die Änderungen hier wie das Hinzufügen really
und Löschen von palace
durch Ersetzen von zu erfassen castle
. Wenn die Absätze grob ausgerichtet wären, wäre dies ziemlich trivial, da es viele Möglichkeiten gibt, Text zu unterscheiden. Da die Absätze jedoch nicht ausgerichtet sind, ist dies nicht der Fall.
Wenn die Dateien klein wären (eine Handvoll Absätze), würde Levenshtein Distance wahrscheinlich gut funktionieren, aber da die Dateien sehr groß sind, wäre es ineffizient, jeden Absatz von Text 1 mit jedem Absatz von Text 2 zu vergleichen, um herauszufinden, welche Absätze übereinstimmen.
Was wären andere Ansätze für dieses Problem, um es effizient zu lösen?
Antworten:
Der Vergleich von 2000 Absätzen mit 2000 Absätzen ergibt nur vier Millionen Vergleiche.
Der Schlüssel zum Problem besteht nicht darin, eine Funktion zu verwenden, die den Levenshtein-Abstand berechnet, sondern eine Funktion, die den Levenshtein-Abstand berechnet, wenn der Abstand unter einem bestimmten Schwellenwert liegt , und fehlschlägt (oder vielmehr + ∞ zurückgibt), wenn der Abstand beträgt größer als die Schwelle.
Dies liegt daran, dass Sie nur an sehr ähnlichen Absätzen interessiert sind. Sie haben überhaupt kein Interesse an der genauen Entfernung zwischen Absätzen, die so unterschiedlich sind, dass sie nichts miteinander zu tun haben. Sobald eine Entfernung hoch genug ist, um uninteressant zu sein, kann die Funktion sofort beendet werden. und dies wird in der Tat meistens sehr früh während der Ausführung der Funktion geschehen.
Je höher der Schwellenwert, desto länger die Laufzeit, desto geringer der Anteil falsch negativer Ergebnisse.
Wenn Sie etwas mehr über die Dokumente wissen (z. B. dass jeder Absatz höchstens einem Absatz im anderen Dokument entspricht), können Sie einen Durchgang mit einem niedrigen Schwellenwert durchführen, die übereinstimmenden Absätze von der weiteren Prüfung ausschließen und einen Durchgang über Ihren jetzt reduzierten Absatz durchführen Korpus mit einem höheren Schwellenwert, schließen Sie diese reduzierten Absätze aus und so weiter.
Implementierungsdetail: Vermutlich würden Sie einen Levenshtein-Abstand eher für Wörter als für Zeichen berechnen. Wenn dies der Fall ist, sollten Sie zuerst jedem Wort eine Nummer zuweisen, indem Sie beispielsweise den gesamten Korpus sortieren, das erste Wort "1", das zweite Wort "2" usw. aufrufen. Auf diese Weise werden Ihre Absatzvergleiche durchgeführt, indem Zahlen statt Wörter verglichen werden, was schneller ist.
quelle
Es könnte möglich sein, einen zusammengesetzten Ansatz zu verwenden. Vielleicht kann jemand darauf aufbauen ...
Hash den Inhalt des Absatzes so, dass Absätze mit nur geringen Unterschieden ähnliche Hashes haben, und ordne dann die Hashes an, um zu bestimmen, welche Absätze mit einer genaueren Methode (diff oder etwas Ähnliches) verglichen werden sollen.
Was wäre zum Beispiel als rudimentärer Hash-Algorithmus, wenn Sie die ASCII-Werte der Zeichen addieren und dann die Summe mit einer großen Zahl wie 2.000.000.000 modulieren? Dies würde dazu führen, dass 2 Absätze mit nur wenigen hinzugefügten oder subtrahierten Wörtern Hash-Werte aufweisen, die wahrscheinlich näher beieinander liegen als Absätze mit sehr unterschiedlichen Wörtern, und daher in der Liste viel näher beieinander liegen als die sehr unterschiedlichen Absätze (könnte man sagen) Hashes in der Nähe sind in diesem Fall erforderlich, reichen jedoch für ähnliche Absätze nicht aus. Offensichtlich müssen Sie den durch Modulo verursachten Wrap-Around berücksichtigen und einen Absatz mit dem Hash-Wert 1.999.999.999 als nur einen Abstand von 1 von einem mit dem Wert 0 usw. betrachten.
Infolgedessen könnte die Anzahl der Vergleiche zwischen Absätzen, die Sie durchführen müssen, erheblich reduziert werden (Sie müssten nicht jeden Absatz in einem Text mit jedem Absatz im anderen Text vergleichen) - Sie könnten einen Absatz mit vergleichen Absätze in Text 2 in der Reihenfolge, in der ihre Hashes nahe beieinander liegen (führen Sie zuerst die nächsten Hash-Werte aus), und rufen Sie hier einen teureren Algorithmus auf, um festzustellen, ob sie "ähnlich genug" sind, um als gleich angesehen zu werden.
quelle