Алгоритмы подобия строк?

Мне нужно сравнить 2 строки и вычислить их сходство, чтобы отфильтровать список наиболее похожих строк.

Например. поиск "собака" вернет

  1. собака
  2. собачий
  3. болото
  4. туман
  5. туманный

Например. поиск "трещины" вернет

  1. трескаться
  2. острить
  3. стойка
  4. Джек
  5. крякать

Я наткнулся на:

Знаете ли вы еще какие-нибудь алгоритмы подобия строк?


person Community    schedule 26.08.2010    source источник
comment
Вики сообщества, потому что на ваш вопрос нет правильного ответа   -  person Joe Phillips    schedule 26.08.2010
comment
Есть множество вопросов, которые уже касаются именно этой темы. Пожалуйста, поищите перед тем, как задать вопрос.   -  person j_random_hacker    schedule 30.08.2010
comment
@j_random_hacker: Вы говорите, куча вопросов? Свяжите меня с вопросом, демонстрирующим хотя бы одну новую технику? И я видел тот, который вы уже связали, прежде чем опубликовать свой вопрос. Я не пытаюсь выполнить простое ранжирование или сортировку, а скорее использую очень точный алгоритм подобия, который возвращал бы результаты, которые я отображал, если бы я выполнял поиск в базе данных словарей.   -  person Robin Rodricks    schedule 31.08.2010
comment
Есть много способов измерить сходство, и вы не объясняете, какой именно тип вы ищете, но, основываясь на ваших примерах и на том факте, что вам не нравится расстояние Левенштейна, я думаю, вам нужна какая-то приблизительная подстрока алгоритм сопоставления. Варианты вашего вопроса - это самая самая популярная тема по тегу algorithm. Вот несколько ссылок:   -  person j_random_hacker    schedule 01.09.2010
comment
stackoverflow.com/questions/49263/   -  person j_random_hacker    schedule 01.09.2010
comment
stackoverflow.com/questions/3326200/   -  person j_random_hacker    schedule 01.09.2010
comment
stackoverflow.com/questions/1938678/   -  person j_random_hacker    schedule 01.09.2010
comment
stackoverflow.com/questions/451884/similar-string-algorithm   -  person j_random_hacker    schedule 01.09.2010
comment
stackoverflow.com/questions/3329297/   -  person j_random_hacker    schedule 01.09.2010


Ответы (5)


Похоже, вам нужно какое-то нечеткое соответствие. Вот реализация на Java некоторого набора показателей сходства http://web.archive.org/web/20081224234350/http://www.dcs.shef.ac.uk/~sam/stringmetrics.html. Вот более подробное объяснение строковых показателей http://www.cs.cmu.edu/~wcohen/postscript/ijcai-ws-2003.pdf это зависит от того, насколько нечеткой и быстрой должна быть ваша реализация.

person Community    schedule 26.08.2010
comment
@PascalKlein Архивная страница доступна на Wayback Machine. Я обновил ссылку на http://web.archive.org/web/20081224234350/http://www.dcs.shef.ac.uk/~sam/stringmetrics.html - person Rob W; 23.03.2013
comment
Существует levenshtein, и вы можете попробовать обрезать его, используя показатель сходства, такой как Wu-Palmer (wup), который использует уважаемый Wordnet. Стэнфордское НЛП для Java - это готово. Также есть шаблон, scipy, numpy; gensim для Python. Вычисление Левенштейна лучше всего производить по диагонали матрицы. - person Andrew Scott Evans; 04.10.2015

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

person Peter    schedule 26.08.2010
comment
Расстояние Левенштейна и все его перестановки (например, Дам-Лев) работают ужасно, даже QuickSilver превосходит его в самых простых сравнениях. См. stackoverflow.com/questions/3338889/ - person Robin Rodricks; 26.08.2010
comment
@Jenko: Вы говорите, что расстояние Левенштейна ужасно работает, но вы не даете никаких критериев для определения того, что хорошо, а что плохо. Учитывая, что расстояние Левенштейна в значительной степени является алгоритмом архетипического сходства строк, вам следует уточнить свой вопрос. - person j_random_hacker; 30.08.2010
comment
@j_random_hacker: Отредактировал ваш пост, чтобы показать вам, почему. Я связал вас с вопросом, который содержал те же результаты, почему вы не прочитали, что я не понимаю. - person Robin Rodricks; 31.08.2010
comment
@Jenko: (1) Это не мой пост. (2) Ошибочность не является значимым критерием. Я понимаю, что вы недовольны результатами, но вам нужно точно объяснить, какие типы сходства вы ищете. И, кстати, вы обычно устанавливаете верхнюю границу расстояния Lev, чтобы в вашем примере возвращались только ответы 1-3. - person j_random_hacker; 01.09.2010
comment
Я использую расстояние Левенштейна для проекта, над которым сейчас работаю, и оно оказалось далеко не идеальным для этого варианта использования. Я обнаружил, что знание того, сколько букв в строке соответствует совпадению, так же важно, как сопоставление тех же букв в строке в том же порядке, что, по сути, является тем, что делает расстояние редактирования. - person Legit Stack; 24.05.2016

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

Сначала перейдите по ссылке в Википедии выше .Tries - это самый быстрый метод сортировки слов (n слов, поиск s, O (n) для создания trie, O (1) для поиска s (или, если вы предпочитаете, если a - средняя длина, O (an) для дерева и O (s) для поиска)).

Быстрая и простая реализация (для оптимизации) вашей проблемы (похожие слова) состоит из

  • Составьте trie со списком слов, указав все буквы спереди и сзади (см. Пример ниже)
  • Для поиска s выполните итерацию от s [0], чтобы найти слово в дереве, затем s [1] и т. Д.
  • В дереве, если число найденных букв равно len (s) - k, отображается слово, где k - допуск (1 буква отсутствует, 2 ...).
  • Алгоритм может быть расширен до слов в списке (см. Ниже)

Например, со словами car, vars.

Построение дерева (большая буква означает, что слово здесь заканчивается, а другая может продолжаться). > - это постиндекс (переход вперед), а < - предварительный индекс (переход назад). В другом примере нам, возможно, придется указать также начальную букву, она здесь не представлена ​​для ясности.
Например, < и > в C ++ будут Mystruct *previous,*next, то есть от a > c < r, вы можете перейти непосредственно от a к c, и наоборот, также с a на R.

  1.  c < a < R
  2.  a > c < R
  3.    > v < r < S
  4.  R > a > c
  5.        > v < S
  6.  v < a < r < S
  7.  S > r > a > v

Если искать строго car, дерево дает вам доступ с 1., и вы найдете car (вы бы также нашли все, что начинается с car, но также что-нибудь с автомобилем внутри - этого нет в примере - но, например, vicar можно было бы найти в c > i > v < a < R).

Чтобы выполнить поиск с допуском неправильной / отсутствующей 1 буквы, вы выполняете итерацию от каждой буквы s и подсчитываете количество последовательных - или пропуская 1 букву - букв, которые вы получаете от s < / em> в дереве.

ищу car,

  • c: поиск в дереве файлов c < a и c < r (пропущенная буква в s). Чтобы принять неправильную букву в слове w, попробуйте на каждой итерации перескакивать на неправильную букву, чтобы увидеть, не отстает ли ar, это O (w). С двумя буквами, O (w ²) и т. Д., Но к дереву можно добавить еще один уровень индекса, чтобы учесть переход по буквам, в результате чего дерево сложный и жадный в отношении памяти.
  • a, затем r: то же, что и выше, но также поиск в обратном направлении

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

person Community    schedule 26.08.2010

Вы могли сделать это:

Foreach string in haystack Do
    offset := -1;
    matchedCharacters := 0;
    Foreach char in needle Do
        offset := PositionInString(string, char, offset+1);
        If offset = -1 Then
            Break;
        End;
        matchedCharacters := matchedCharacters + 1;
    End;
    If matchedCharacters > 0 Then
       // (partial) match found
    End;
End;

С помощью matchedCharacters вы можете определить «степень» соответствия. Если он равен длине иглы, все символы в игле также находятся в строке. Если вы также сохраняете смещение первого сопоставленного символа, вы также можете отсортировать результат по «плотности» сопоставленных символов, вычитая смещение первого сопоставленного символа из смещения последнего сопоставленного символа смещение ; чем меньше разница, тем плотнее совпадение.

person Community    schedule 26.08.2010
comment
@Jenko: Что ты имеешь в виду? Поиск является линейным, поэтому проверяется каждая строка в списке строк. - person Gumbo; 26.08.2010
comment
Что значит PositionInString? - person Moritz Schmitz v. Hülst; 16.06.2015
comment
@ MoritzSchmitzv.Hülst PositionInString - это функция, которая возвращает позицию индекса char в string, начиная с offset. - person Gumbo; 16.06.2015

person    schedule
comment
Я думаю, он просит алгоритмы, а не реализацию решения. - person Giulio Caccin; 25.07.2017