Levenshtein-Distanz-Visualisierer

Gib zwei Zeichenketten ein, um ihre Levenshtein- (Editier-)Distanz zu sehen — die minimale Anzahl an Einzelzeichen-Änderungen, um die eine in die andere zu überführen.

Interaktive Simulation wird geladen...

Lektion

Die Theorie — Levenshtein-Distanz-Visualisierer

Die Levenshtein-Distanz zwischen zwei Zeichenketten ist die kleinste Zahl von Einzelzeichen-Bearbeitungen, die eine in die andere überführt, wobei eine Bearbeitung ein Einfügen, ein Löschen oder ein Ersetzen ist. Sie ist ein Minimum über alle denkbaren Wege, das zu tun — und genau deshalb ist sie mit bloßem Auge schwer und mit einem Gitter leicht zu bestimmen: Es gibt unvorstellbar viele Bearbeitungsfolgen, und dieses Verfahren findet die kürzeste, ohne eine einzige davon aufzulisten.

Was die einzelnen Symbole bedeuten

m, n
die Längen der beiden Zeichenketten A und B.
D(i, j)
der günstigste Weg, die ersten i Zeichen von A in die ersten j Zeichen von B zu überführen. Eine Zelle der Tabelle auf dieser Seite.
[aᵢ ≠ bⱼ]
kostet 1, wenn sich die beiden Zeichen unterscheiden, und 0, wenn sie übereinstimmen — der Preis der Ersetzung, der entfällt, wenn nichts zu ersetzen ist.
d
die Antwort, D(m, n): die Zelle unten rechts.

Woher die Formel kommt

  1. Lege fest, was eine Zelle bedeutet, bevor du irgendeine füllst. Sei D(i, j) die kleinste Zahl von Bearbeitungen, die die ersten i Zeichen von A in die ersten j von B überführt. Gesucht ist D(m, n), und jede andere Zelle ist eine kleinere Fassung derselben Frage.
  2. Die Ränder erfordern kein Nachdenken. Um die ersten j Zeichen von B aus dem Nichts aufzubauen, musst du alle j einfügen, also D(0, j) = j. Um die ersten i Zeichen von A auf nichts zu reduzieren, musst du alle i löschen, also D(i, 0) = i. Das ist die oberste Zeile und die linke Spalte des Gitters — und der Grund, warum sie einfach hochzählen.
  3. Nun der Schritt, der die ganze Arbeit leistet. Nimm irgendeine optimale Folge für D(i, j) und betrachte nur ihren letzten Zug. Es gibt genau drei Möglichkeiten: Sie hat aᵢ gelöscht und damit die Aufgabe D(i−1, j) übrig gelassen; sie hat bⱼ eingefügt und D(i, j−1) übrig gelassen; oder sie hat aᵢ mit bⱼ gepaart und D(i−1, j−1) übrig gelassen. Jede davon ist eine bereits gefüllte Zelle.
  4. Also ist die Zelle das Günstigste der drei: D(i, j) = min( D(i−1, j) + 1, D(i, j−1) + 1, D(i−1, j−1) + [aᵢ ≠ bⱼ] ). Fülle das Gitter von links nach rechts und von oben nach unten, dann sind bei jeder Zelle ihre drei Nachbarn schon bekannt. Das ist der ganze Algorithmus — m × n Zellen, drei Vergleiche je Zelle.

So liest du, was du siehst

Das Gitter auf dieser Seite ist genau diese Tabelle. Zeilen sind A, Spalten sind B, und die zusätzliche Zeile und Spalte oben links sind die leeren Präfixe aus Schritt 2 — deshalb zählen sie 0, 1, 2, 3. Die Einfärbung ist der Wert: der blasse diagonale Korridor ist dort, wo die beiden Zeichenketten noch günstig übereinstimmen. Fahre über eine Zelle oder tippe sie an, und das Feld darunter buchstabiert Schritt 3 für genau diese Zelle aus — die drei Kandidaten, jeder mit seiner Rechnung, der Sieger hervorgehoben. Die farbige Linie ist eine optimale Route, von unten rechts zurückverfolgt, und der Zuordnungsstreifen darunter ist dieselbe Route in Zeichen geschrieben.

Setzt voraus
Jede Bearbeitung kostet genau 1, und Zeichen werden auf exakte Gleichheit geprüft — keine Groß-/Kleinschreibungsangleichung, keine Unicode-Normalisierung, keine Vorstellung davon, welche Zeichen einander ähneln. Zwei Folgen sind hier sichtbar. Gezählt werden hier UTF-16-Codeeinheiten, nicht das, was du Buchstaben nennen würdest: Tippe ein einzelnes Emoji in ein Feld, und die Tabelle ist 3 × 1, denn ein Emoji sind zwei Einheiten, und es zu löschen kostet 2. Und café mit vorkomponiertem é gegen café als e plus kombinierendem Akzent ergibt Distanz 2, obwohl beide auf dem Bildschirm identisch aussehen.
Versagt, wenn
Das Gitter hat m × n Zellen, der Aufwand wächst also mit dem Produkt der Längen. Für zwei Wörter ist das kein Problem, für eine Anfrage gegen ein Wörterbuch mit einer Million Einträgen ist es aussichtslos — das sind eine Million Gitter. Die naheliegende Antwort wäre ein raffinierterer Algorithmus, und die Überraschung ist, dass es im Wesentlichen keinen gibt: Backurs und Indyk zeigten 2015, dass eine deutlich subquadratische Editierdistanz die starke Exponentialzeit-Hypothese widerlegen würde. Echte Rechtschreibprüfungen unterbieten die Schranke nicht, sie weichen ihr aus — sie brechen ab, sobald die Distanz eine kleine Grenze überschreitet, oder indizieren so, dass fast jeder Kandidat nie verglichen wird.

Das Gitter ist klein, weil jede Teilfrage nur einmal gestellt wird 🖖

Das Durchsuchen aller möglichen Folgen von Editierschritten ist aussichtslos — die Anzahl der Möglichkeiten explodiert mit der Länge der Wörter. Der entscheidende Einfall lautet: Für jedes Paar von Präfixen gibt es genau eine optimale Antwort, und diese ändert sich nie, egal was später in der Zeichenkette passiert. Statt also Abfolgen zu durchsuchen, füllt man ein Gitter: eine Zeile pro Buchstabe des ersten Wortes, eine Spalte pro Buchstabe des zweiten, plus eine leere Zeile und Spalte für das leere Präfix. Aus kitten das Wort sitting zu machen, erfordert daher 7 × 8 = 56 Zellen; jede einzelne wird durch einen Blick auf drei bereits gefüllte Nachbarn bestimmt, und die Antwort 3 wartet in der rechten unteren Ecke. Der Aufwand wächst mit dem Produkt der beiden Längen, nicht mit der Anzahl der Editierwege.

Eine Vertauschung kostet zwei Bearbeitungen, solange du nichts anderes sagst 🖖

Gib form und from ein, und Levenshtein antwortet 2. Der Algorithmus hat keinen Begriff davon, dass die Buchstaben vertauscht wurden, also bezahlt er zwei Ersetzungen. Vertauschte Buchstaben gehören aber zu den häufigsten Tippfehlern überhaupt, und genau deshalb hat Damerau einen vierten Zug ergänzt: Wenn die beiden Zeichen, die du brauchst, genau die beiden sind, die du in umgekehrter Reihenfolge hast, dann nimm beide zum Preis von einem. Wechsle oben das Kostenmodell, und dasselbe Paar kostet 1. An den Wörtern hat sich nichts geändert — an der Preisliste schon. Das lohnt sich zu merken, wo immer eine Editierdistanz als Ähnlichkeitsmaß dient, denn die Zahl ist ebenso eine Eigenschaft des gewählten Kostenmodells wie der beiden Zeichenketten.

Die schnelle Variante kann dieses Bild nicht zeichnen 🖖

Jede Zelle braucht nur die Zeile über sich und die Zelle links von sich; die weiter zurückliegenden Zeilen gewinnen nichts dadurch, dass sie bleiben. Reale Implementierungen nehmen dieses Angebot an und halten zwei Zeilen statt der ganzen Tabelle, was den Speicher von m × n auf min(m, n) bringt — bei zwei Zeichenketten von tausend Zeichen von rund einer Million Zellen auf zweitausend. Aufgegeben wird dabei genau das, was oben gezeichnet ist. Die Distanz überlebt in der letzten Zelle, aber der Weg dorthin lag in den überschriebenen Zeilen. Eine Zwei-Zeilen-Implementierung kann dir also sagen, dass zwei Zeichenketten drei Bearbeitungen auseinanderliegen, aber nicht, welche drei. Den Weg ohne das volle Gitter zurückzuholen ist schwerer, als es aussieht; Hirschberg löste es 1975, indem er die Tabelle in der Mitte teilte und in beide Hälften hinein rekursiv absteigt.

Aufgabe vollständig gelöst

  1. Die günstigste Editiersequenz, um kitten in sitting umzuwandeln 5 Schritte

    Wandeln Sie kitten in sitting um. Finden Sie die günstigste Editiersequenz und beweisen Sie, dass keine günstigere existiert — berechnen Sie dann, was dies kostet, wenn das zweite Wort ein ganzes Wörterbuch ist.

    1. Die Rekursionsformel ist bereits der gesamte Algorithmus. Jede Zelle fragt, was es kostet, hierher durch Löschen, Einfügen oder Ausrichten der beiden aktuellen Zeichen zu gelangen — wobei die letzte Option kostenlos ist, wenn sie übereinstimmen. Eine Zelle benötigt nur die drei Nachbarn oberhalb und zu ihrer Linken, sodass ein einziger Durchlauf von links nach rechts die Tabelle füllt.

    2. Bevor irgendetwas ausgefüllt wird, schränken Sie das Ergebnis ein. Die Längen unterscheiden sich um eins, sodass mindestens eine Einfügung unvermeidbar ist; und das vollständige Überschreiben des Wortes kostet 7. Das Ergebnis liegt dazwischen, was die meisten Vermutungen bereits ausräumt.

    3. Drei Editierungen reichen aus: Ersetzen k → s, Ersetzen e → i, Einfügen g. Jede ist eine einzelne zulässige Editieroperation, und die Kette endet auf dem Zielwort.

    4. Das Vorweisen von drei Editierschritten beweist nur, dass die Distanz höchstens 3 beträgt. Die Tabelle beweist, dass sie exakt 3 ist, weil jede Route zur untersten rechten Ecke bewertet und an jeder Zelle auf dem Weg das Minimum genommen wird. Das ist der Unterschied zwischen dem Finden einer Antwort und dem Wissen, dass sie nicht übertroffen werden kann.

    5. Der Aufwand beträgt eine Zelle pro Zeichenpaar — hier 42, was praktisch nichts ist. Bei einem Wörterbuch mit 100 000 Wörtern zu je sieben Buchstaben sind das über vier Millionen Zell-Updates für eine einzige Abfrage.

    Antwort

    Das Tool gibt 3 und eine Ähnlichkeit von 57,14% aus, was 1 − 3/7 entspricht: die durch das längere Wort normalisierte Distanz. Beide Werte stammen aus einer Tabelle, die Sie in einer Minute von Hand ausfüllen können. Was nicht skaliert, ist die Tabelle — der Aufwand beträgt Θ(mn), sodass das Verdoppeln beider Zeichenketten den Aufwand vervierfacht, und jede Rechtschreibprüfung, die Sie je benutzt haben, ist darauf ausgelegt, genau dies zu vermeiden. Der Ausweg ist nicht eine schnellere Tabelle. Es ist die Tatsache, dass Levenshtein die Dreiecksungleichung erfüllt, sodass d(a, c) ≤ d(a, b) + d(b, c) einem Index erlaubt zu beweisen, dass ein Kandidat zu weit entfernt ist, ohne jemals zu messen, wie weit.

Quellen (4)

Beispielaufgaben

  • kitten → sitting - kitten → sitting ist der Lehrbuchfall, und die Antwort lautet 3: zwei Ersetzungen und eine Einfügung, 57,14% Ähnlichkeit
  • book → back - book → back sind 2 Schritte zwischen zwei Wörtern mit vier Buchstaben, ausgewiesen als 50,00% Ähnlichkeit
  • Saturday → Sunday - Saturday → Sunday braucht 3 Bearbeitungen und ergibt 62,50% Ähnlichkeit, zwei davon Löschungen
  • form → from (Vertauschung) - form → from ist unter Damerau–Levenshtein eine einzige Vertauschung, die das Werkzeug als 75,00% Ähnlichkeit liest
  • DNA-Vergleich - GATTACA → GCATGCG braucht 4 Schritte und 42,86% — dasselbe Maß, angewandt auf Sequenzdaten