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

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

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

Любые идеи приветствуются!

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

Ответы

Ответ 1

На самом деле я написал код для этого на следующий день:

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

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

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

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

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

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

Ответ 4

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