Функция, возвращающая сходство между текстами?

считайте, что у меня есть

string1 = "hello hi goodmorning evening [...]"

и у меня есть несколько второстепенных ключевых слов

compare1 = "hello evening"
compare2 = "hello hi"

Мне нужна функция, которая возвращает соответствие между текстом и ключевыми словами. Пример:

function(string1,compare1);  // returns: 4
function(string1,compare2);  // returns: 5 (more relevant)

Обратите внимание: 5 и 4 приведены только для примера.

Вы могли бы сказать - напишите функцию, которая подсчитывает вхождения - но для этого примера это не сработает, потому что оба имеют 2 вхождения, но compare1 менее актуален, потому что «привет, вечер» точно не встречается в строке1 (2 слова привет и вечер более далекий, чем привет привет)

есть ли какой-нибудь известный алгоритм для этого?

ДОБАВИТЬ1:

алгоритмы вроде Edit Distance в этом случае НЕ будут работать. Поскольку строка1 - это полный текст (например, 300-400 слов), а сравниваемые строки - максимум 4-5 слов.


person dynamic    schedule 24.01.2011    source источник
comment
Вы ищете простое сравнение строк на расстоянии редактирования или полную семантическую эквивалентность? например кошка больше похожа на телегу или кошку?   -  person Ian Mercer    schedule 25.01.2011
comment
ни один из обоих .. Мне нужно что-то вроде подсчета вхождений + дать вес на основе расстояний слов (как я объяснял ранее: строка1 - это статья с 300-400 словами, а сравниваемые строки - всего 3-4 слова)   -  person dynamic    schedule 25.01.2011
comment
Ваши ключевые слова всегда попадают в пары? Что важнее: наличие большего количества подходящих слов или лучшая близость?   -  person Michael J. Barber    schedule 27.01.2011
comment
1. не всегда попарно, строка сравнения может содержать до 5-6 слов 2. 50% -50%   -  person dynamic    schedule 01.02.2011


Ответы (7)


Алгоритм динамического программирования

Кажется, то, что вы ищете, очень похоже на то, что Смит – Уотерман алгоритм делает.

Из Википедии:

Алгоритм был впервые предложен Темплом Ф. Смитом и Майклом С. Уотерманом в 1981 году. Подобно Needleman-Wunsch, разновидностью которого является алгоритм Смита-Уотермана, алгоритм динамического программирования . Таким образом, он обладает желаемым свойством, заключающимся в том, что он гарантирует оптимальное локальное выравнивание по отношению к используемой системе оценки (которая включает в себя матрицу замещения и схему оценки пробелов).

Давайте посмотрим на практический пример, чтобы вы могли оценить его полезность.

Допустим, у нас есть текст:

text = "We the people of the United States, in order to form a more 
perfect union, establish justice, insure domestic tranquility, 
provide for the common defense, 

  promote the general welfare, 

  and secure the blessings of liberty to ourselves and our posterity, 
do ordain and establish this Constitution for the United States of 
America.";  

Я выделил сегмент, который мы собираемся сопоставить, просто для удобства чтения.

Мы сравним сходство (или сходство) со списком строк:

list = {
   "the general welfare",
   "my personal welfare",
   "general utopian welfare",
   "the general",
   "promote welfare",
   "stackoverflow rulez"
   };  

У меня уже реализован алгоритм, поэтому я рассчитаю сходство и нормализую результаты:

sw = SmithWatermanSimilarity[ text, #] & /@ list;
swN = (sw - Min[sw])/(Max[sw] - Min[sw])  

Затем мы наносим результаты на график:

введите описание изображения здесь

Думаю, это очень похоже на ваш ожидаемый результат.

HTH!

Некоторые реализации (с исходным кодом)

person Dr. belisarius    schedule 03.02.2011
comment
Это могло бы быть решением! Но почему функция ur называется SmithWatermanSimilarity, а не просто SmithWaterman: я имею в виду, есть ли у вас какие-то настройки? В любом случае у вас есть описание псевдокода для этого? Так что я могу переводить на свой язык (php) - person dynamic; 03.02.2011
comment
@ yes123 В конце моего ответа есть несколько ссылок (вы можете найти много), включая три реализации и два учебных ресурса. Я не могу предоставить свой, потому что он не с открытым исходным кодом. - person Dr. belisarius; 03.02.2011
comment
Ах хорошо. Возможно, я попробую реализацию cuda или java, чтобы увидеть, соответствует ли она моим потребностям (например, вашему решению). Если я переведу на php, я опубликую здесь ссылку, спасибо - person dynamic; 03.02.2011
comment
Я тестирую некоторые реализации Java. Кажется, что эти реализации рассматривают символы, а не слова входа. Это большая проблема для меня - person dynamic; 03.02.2011
comment
@ yes123 тоже хорошо работает со словами, попробуйте. Он предназначен для сопоставления последовательностей ДНК, которые похожи на слова - person Dr. belisarius; 03.02.2011
comment
@ yes123 После тестирования, пожалуйста, вернитесь и оставьте комментарии. Мне очень интересно узнать, как алгоритм отражает ваши конкретные требования! - person Dr. belisarius; 04.02.2011
comment
реализации, которые я использую в php, дают мне одинаковую оценку 1 для общего благосостояния и в целом, если вы хотите увидеть код php, я опубликую ссылку. - person dynamic; 05.02.2011
comment
@ yes123 Итак, он очень сильно сломан, потому что такое выравнивание - самая основная вещь, которую алгоритм делает правильно. Вы можете проверить на baba.sourceforge.net, какими должны быть промежуточные результаты и как увеличивается длина соответствия текста. счет. - person Dr. belisarius; 05.02.2011
comment
вот код: google. com / codesearch / p? hl = en # I08I-vVKhsw / trunk / biostor / swa.php жаль, это не так уж и здорово = / - person dynamic; 05.02.2011
comment
@ yes123 Код работает некорректно. Хорошо работает только для идеального выравнивания. :( - person Dr. belisarius; 05.02.2011
comment
Я не понимаю, почему такие важные алгоритмы для поиска (оценка на основе близости) не так известны, особенно для php, который работает с веб-сайтом / search = / - person dynamic; 05.02.2011
comment
@ yes123 Вы можете попробовать найти алгоритм Нидлмана-Вунша, но этот гораздо лучше для ваших целей. Я не разбираюсь в PHP, поэтому ничем не могу помочь. Прости. - person Dr. belisarius; 05.02.2011
comment
ничего ни для рукодельника. Проблема здесь в том, что эти 2 алгоритма используются в биоинформатике ... поэтому в PHP они полностью неизвестны. - person dynamic; 06.02.2011
comment
ну, я должен написать функцию самостоятельно, чтобы сделать это. Результаты очень близки к вашим. Я хотел бы поделиться с вами своим решением и обсудить его, можем ли мы поговорить наедине (электронная почта, чат, msn, fb)? это небольшое место для комментариев здесь меня ранит. - person dynamic; 06.02.2011
comment
@ yes123 Желательно, чтобы общение происходило через Stack Overflow, чтобы сообщество могло поделиться решением вашей проблемы. Мы здесь для того, чтобы сделать мир программирования лучше, публично делясь своими знаниями. - person George Stocker; 07.02.2011
comment
@george, я полностью согласен. но это маленькое пространство совершенно ужасно, чтобы обсуждать такие вещи. таким образом, stackoverflow (по правилам) - это только сайт вопросов и ответов, а не доска обсуждений :) (и поэтому комментарии здесь так ограничены) - person dynamic; 07.02.2011
comment
@belisarius :( ты там? :( - person dynamic; 09.02.2011
comment
@ yes123 да, я здесь. Проверьте, можете ли вы создать приватную чат-комнату на chat.stackoverflow.com, и пригласите меня - person Dr. belisarius; 09.02.2011
comment
@belisarius не может этого сделать в чате :( В любом случае, я создал для вас ссылку. Зайдите сюда, вы можете протестируйте мой алгоритм. Как вы можете видеть (внизу страницы кодовой панели), общее благосостояние получило наивысший балл в 8. Если у вас есть какие-либо предложения, сообщите мне. Обратите внимание, что я не использовал ни один из хорошо известных алгоритмов .. Я просто написал это сам - person dynamic; 10.02.2011
comment
@ yes123 Если ваш алгоритм дает стабильные результаты, вперед! Это, конечно, не алгоритм SW и, похоже, слишком мало подходит для более длительных матчей. - person Dr. belisarius; 10.02.2011
comment
@belisarius да, в настоящее время я использую его с хорошими результатами. В любом случае спасибо за вашу помощь. - person dynamic; 10.02.2011
comment
@belisarius Эти реализации алгоритмов Смита – Уотермана и Нидлмана-Вунша очень более чистая отправная точка реализации Python, чем та, на которую вы ссылаетесь для SW в своем сообщении. - person dtanders; 31.05.2012
comment
@dtanders Спасибо! Не стесняйтесь редактировать мой ответ, если считаете, что они лучше тех, что я нашел - person Dr. belisarius; 31.05.2012

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

Сложнее всего придумать метрику, определяющую сродство так, как вы хотите.

Альтернативой является просмотр скользящего окна и оценка в зависимости от того, сколько слов в ваших данных compare_x находится в окне. Окончательный результат - это сумма.

person I GIVE CRAP ANSWERS    schedule 25.01.2011
comment
Хм, даже если это интересно, я не думаю, что вы можете использовать это скользящее окно, потому что вы не можете выбрать размер окна, который alyawys работает imo. Я думал примерно так: сначала подсчитывает только вхождения, а затем удаляет некоторые точки в зависимости от того, сколько символов существует между найденными ключами. Но я не могу поверить, что еще нет известного алгоритма для этой работы ... Это так важно в материалах, связанных с поиском. Regsrding другое решение с использованием ngrams, я не имею четкого представления о том, как это сделать - person dynamic; 25.01.2011
comment
Нет однозначного решения, потому что разные метрики нужны для разных целей. - person I GIVE CRAP ANSWERS; 25.01.2011
comment
почему ты сказал это? Я почти уверен, что кто-то уже написал для этого алгоритмы (не думаю, что это было бы слишком сложно). Я нашел здесь математическое решение проблемы: - person dynamic; 25.01.2011

py-editdist предоставит вам расстояние редактирования Левенштейна между двумя строками, которое может оказаться полезным. .

См .: http://www.mindrot.org/projects/py-editdist/

Пример кода с этой страницы:

import editdist

# Calculate the edit distance between two strings
d = editdist.distance("abc", "bcdef")

Связанный: https://stackoverflow.com/questions/682367/good-python-modules-for-fuzzy-string-comparison

person payne    schedule 24.01.2011

Я думаю, что здесь есть довольно хороший и полный ответ на этот вопрос http://answers.google.com/answers/threadview?id=337832.

Извините за ответы Google!

person macarthy    schedule 02.02.2011
comment
Половина ссылки на этой странице не работает. А другая половина вообще не говорит о близости - person dynamic; 02.02.2011
comment
Если вы имеете в виду близость, как по смыслу, - person macarthy; 04.02.2011

Здесь вы можете найти список показателей для расчета расстояния между строками и java-библиотеку с открытым исходным кодом, которая просто делает это. http://en.wikipedia.org/wiki/String_metric В частности, обратите внимание на Алгоритм Смита – Уотермана, имея в виду, что то, что они называют «алфавитом», может быть составлено из того, что мы называем строками: итак, учитывая алфавит

{A = "hello", B = "hi",C = "goodmorning",D = "evening"}

и называется d расстоянием, ваша функция пытается вычислить

d(ABCD,AB) vs d(ABCD,AC)
person kaharas    schedule 27.01.2011
comment
ХМ, я читал, что Смит – Уотерман отлично работает с персонажами .. Мне нужен этот алгоритм для текста = / - person dynamic; 31.01.2011
comment
Как указывалось ранее, думайте о каждом слове как о согласном знаке, и все готово. - person kaharas; 31.01.2011
comment
Хм, так я должен построить свой алфавит на основе моего текста и моей строки сравнения и передать их алгоритмам? Я не уверен, что это сработает, потому что алгоритмы поддерживают такие вещи, как вставка / удаление, которые работают для символов - person dynamic; 31.01.2011

Что ж, вы можете посчитать вхождения кусков сравниваемого текста, то есть:

«a-b-c» -> «a», «b», «c», «a-b», «b-c», «a-b-c» (возможно «a-c», если вы этого хотите)

А затем подсчитайте вхождения каждого из них и просуммируйте их, возможно, с весом (длина строки) / (длина всей строки).

Тогда вам просто нужен способ произвести эти части и провести проверку для всех из них.

person TaslemGuy    schedule 31.01.2011

Хотя расстояние Левенштейна в его нынешнем виде может не соответствовать вашим целям, его изменение может: Попробуйте реализовать это путем раздельного хранения вставок, удалений и замен.

Тогда расстояние будет суммой следующих величин:

  • Все замены
  • The number of spaces minus one in each set of consecutive insertions/deletions:
    • (In your case: " hi goodmorning " only counts as two edits, and ' [...] ' counts as one.)

Конечно, вам придется это протестировать, но если это не сработает, попробуйте просто использовать сумму последовательных вставок / удалений (так что «привет, доброе утро» - это всего лишь одно изменение).

ИЗМЕНИТЬ

P.S .: это предполагает относительно серьезные изменения в том, как работает Левенштейн, вам нужно сначала «выровнять» свои данные (выяснить, где существует значительное (более двух символов) перекрытие, и вставить «нулевые» символы, которые будут считаться вставками).

Кроме того, это всего лишь непроверенная идея, поэтому приветствуются любые идеи по улучшению.

person Chris Pfohl    schedule 01.02.2011