Вычислить косинусное сходство с учетом 2 строк предложения

С Python: tf-idf-Косинус: найти сходство документов, можно рассчитать сходство документов с помощью Косинуса TF-idf. Без импорта внешних библиотек это какие-либо способы вычисления косинусного сходства между 2 строками?

s1 = "This is a foo bar sentence ."
s2 = "This sentence is similar to a foo bar sentence ."
s3 = "What is this string ? Totally not related to the other two lines ."

cosine_sim(s1, s2) # Should give high cosine similarity
cosine_sim(s1, s3) # Shouldn't give high cosine similarity value
cosine_sim(s2, s3) # Shouldn't give high cosine similarity value

4 ответов


простая реализация pure-Python будет:

import re, math
from collections import Counter

WORD = re.compile(r'\w+')

def get_cosine(vec1, vec2):
     intersection = set(vec1.keys()) & set(vec2.keys())
     numerator = sum([vec1[x] * vec2[x] for x in intersection])

     sum1 = sum([vec1[x]**2 for x in vec1.keys()])
     sum2 = sum([vec2[x]**2 for x in vec2.keys()])
     denominator = math.sqrt(sum1) * math.sqrt(sum2)

     if not denominator:
        return 0.0
     else:
        return float(numerator) / denominator

def text_to_vector(text):
     words = WORD.findall(text)
     return Counter(words)

text1 = 'This is a foo bar sentence .'
text2 = 'This sentence is similar to a foo bar sentence .'

vector1 = text_to_vector(text1)
vector2 = text_to_vector(text2)

cosine = get_cosine(vector1, vector2)

print 'Cosine:', cosine

принты:

Cosine: 0.861640436855

формула Косинуса, используемая здесь, описана здесь.

это не включает взвешивание слов tf-idf, но для того, чтобы использовать tf-idf, вам нужно иметь достаточно большой корпус, из которого можно оценить веса tfidf.

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


короткий ответ: "Нет, это невозможно сделать принципиальным образом, который работает даже отдаленно хорошо". Это нерешенная проблема в исследованиях обработки естественного языка, а также является предметом моей докторской работы. Я очень кратко подытожу, где мы находимся, и укажу вам на несколько публикаций:

смысл слова

наиболее важным предположением здесь является то, что можно получить вектор, представляющий каждый слово в предложении в вопросе. Этот вектор обычно выбирается для захвата контекстов, в которых может появиться слово. Например, если мы рассмотрим только три контекста "есть", "красный" и "пушистый", слово "кошка" может быть представлено как [98, 1, 87], потому что, если бы вы прочитали очень длинный кусок текста (несколько миллиардов слов не редкость по сегодняшнему стандарту), слово "кошка" появилось бы очень часто в контексте "пушистый" и "есть", но не так часто в контексте "красный". Точно так же" собака "может быть представлена как [87,2,34], а" зонтик " - как [1,13,0]. Представляя эти векторы как точки в 3D-пространстве, " кошка "явно ближе к" собаке", чем к" зонтику", поэтому" кошка "также означает нечто более похожее на" собаку", чем на"зонтик".

эта линия работы была исследована с начала 90-х годов (например,этой работа Greffenstette) и дала некоторые удивительно хорошие результаты. Например, вот несколько случайных записей в тезаурусе, который я недавно построил, прочитав на своем компьютере Википедию:

theory -> analysis, concept, approach, idea, method
voice -> vocal, tone, sound, melody, singing
james -> william, john, thomas, robert, george, charles

эти списки похожих слов были получены полностью без вмешательства человека - вы вводите текст и возвращаетесь через несколько часов.

проблема с ключевыми словами

вы можете спросить, почему мы не делаем то же самое для более длинных фраз, таких как "рыжие лисы любят фрукты". Это потому, что нам не хватает текста. Для того, чтобы надежно установите, на что похож X, нам нужно увидеть много примеров использования X в контексте. Когда X-это одно слово, такое как" голос", это не слишком сложно. Однако по мере того, как X становится длиннее, шансы найти естественные вхождения X становятся экспоненциально медленнее. Для сравнения, Google имеет около 1B страниц, содержащих слово " fox "и ни одной страницы, содержащей "имбирные лисы любят фрукты", несмотря на то, что это совершенно правильное английское предложение, и мы все понимаем, что это средства.

состав

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

самый простой и очевидный способ-добавить или умножить отдельные векторы слов вместе. Это приводит к нежелательному побочному эффекту, который "кошки chase dogs " и "собаки преследуют кошек" будут означать то же самое для вашей системы. Кроме того, если вы умножаете, вы должны быть очень осторожны, или каждое предложение будет представлено [0,0,0,...,0], который побеждает точку.

более дальнеишее чтение

Я не буду обсуждать более сложные методы композиции, которые были до сих пор предложены. Я предлагаю вам прочитать Кэтрин Эрк "векторные пространственные модели значения слова и значения фразы: опрос". Это очень хороший опрос высокого уровня, чтобы вы начали. К сожалению, это не свободно доступны на веб-сайте издателя, напишите автору напрямую, чтобы получить копию. В этой статье вы найдете ссылки на многие другие конкретные методы. Более понятные-по Митчел и Lapata (2008) и Барони и Зампарелли (2010).


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


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

cos(q, d) = sim (q, d) = (q · d)/(|q||d|) = (sum(qi, di)/(sqrt(sum(qi2)))*(sqrt(sum (vi2))) где i = 1 к v)

  • qi-это вес TF-idf термина i в запросе.
  • di-это ТФ-Армии обороны Израиля
  • вес термина I в документе. | q |и| d / длины q и Д.
  • это косинусное сходство q и d . . . . . . или, эквивалентно, косинус угла между q и d.

пожалуйста, не стесняйтесь просматривать мой код здесь. Но сначала вам нужно будет загрузить пакет anaconda. Он автоматически установит вам путь python в Windows. Добавьте этот интерпретатор python в Eclipse.


Ну, если вы знаете о слово вложениями как перчатка/Word2Vec/Numberbatch, ваша работа наполовину сделана. Если нет, позвольте мне объяснить, как это можно решить. Преобразуйте каждое предложение в токены слов и представляйте каждый из этих токенов как векторы высокой размерности (используя предварительно обученные вложения слов, или вы могли бы железнодорожный их даже себе!). Итак, теперь вы просто не фиксируете их поверхностное сходство, а скорее извлекаете значение каждого слова, которое составляет предложение в целом. После этого вычислите их косинусное сходство,и вы установите.