Что такое хороший алгоритм для прохождения Trie для проверки орфографических предложений?

предполагая, что построена общая Трие словарных слов, какой был бы лучший метод для проверки 4 случаев орфографических ошибок - подстановки, удаления, транспозиции и вставки во время обхода?

один из методов состоит в том, чтобы выяснить все слова в пределах N редактировать расстояния от данного слова, а затем проверить их в Trie. Это неплохой вариант, но лучшая интуиция здесь, похоже, использует метод динамического программирования (или рекурсивного эквивалента) для определения лучшие под-попытки после изменения слов во время обхода.

любые идеи будут приветствоваться!

PS, оценил бы фактические входы, а не только ссылки в ответах.

4 ответов


Я на самом деле написал код, чтобы сделать это на днях:

https://bitbucket.org/teoryn/spell-checker/src/tip/spell_checker.py

Он основан на коде Питера Норвига (http://norvig.com/spell-correct.html) но сохраняет словарь в trie для поиска слов в пределах заданного расстояния редактирования быстрее.

алгоритм ходит trie рекурсивно применяя возможные изменения (или нет) на каждом шаге по пути потребление букв из входного слова. Параметр рекурсивного вызова указывает, сколько еще изменений можно внести. Trie помогает сузить пространство поиска, проверяя, какие буквы действительно могут быть достигнуты из нашего данного префикса. Например, при вставке символа вместо добавления каждой буквы в алфавит мы добавляем только те буквы, которые доступны из текущего узла. Не делать правку эквивалентно взятию ветви из текущего узла в trie вдоль текущей буквы из ввод слова. Если этой ветви там нет, мы можем вернуться назад и избежать поиска возможно большого пространства, где не может быть найдено никаких реальных слов.


Я думаю, что вы можете сделать это с помощью простого поиска по ширине на дереве: выберите порог количества ошибок, которые вы ищете, просто запустите буквы слова, которые будут соответствовать по одному за раз, генерируя набор (префикс, subtrie) пар, достигших до сих пор соответствия префиксу, и, пока вы находитесь ниже порога ошибки, добавьте в свой набор следующих подцелей:

  1. нет ошибки в этом месте символа: добавьте подцель trie в следующий символ в слове
  2. вставленный, удаленный или замененный символ в этом месте: найдите соответствующий trie там и увеличьте количество ошибок;
  3. не дополнительная цель, но обратите внимание, что транспозиции являются либо вставкой, либо удалением, которое соответствует более раннему удалению или вставке: если этот тест удерживается, то не увеличивайте количество ошибок.

Это кажется довольно наивным: есть ли проблема с этим, что привело вас к мысли о динамическом программировании?


предполагая, что каждый последующий символ в вашем слове представляет один уровень в вашем дереве, у вас есть пять случаев для проверки каждого символа (совпадение, удаление, вставка, подстановка и транспозиция). Я предполагаю, что транспозиции-это два смежных символа.

вам понадобится функция (CheckNode), которая принимает узел дерева и символ для проверки. Он должен будет вернуть набор (дочерних/Гранд-дочерних) узлов, представляющих совпадения.

вам понадобится функция (CheckWord), который принимает слово. Он проверяет каждый символ по очереди против набора узлов. Он вернет набор (листовых) узлов, представляющих сопоставленные слова.

идея в том, что каждый уровень в дереве (ребенок, внук и т. д.), соответствует положению символа в слове. Если вы вызываете узел дерева верхнего уровня, Уровень 0, то у вас будет уровень 1, Уровень 2 и т. д.

ясно, что для Слова без ошибок существует один к одному соответствие между позицией символа и уровень на дереве.

для удаления необходимо пропустить уровень в дереве.

для вставок необходимо пропустить символ в слове.

для подстановок вам нужно пропустить как уровень, так и символ.

для транспозиций вам нужно (временно) поменять местами символы в слове.


взгляните на вычисление расстояние Левенштейна который обеспечивает решение динамического программирования для нахождения расстояния между двумя последовательностями.