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

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

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
58 голосов | спросил alvas 2 MarpmSat, 02 Mar 2013 14:06:29 +04002013-03-02T14:06:29+04:0002 2013, 14:06:29

5 ответов


0

Простая реализация на чистом 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.

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

ответил vpekar 2 MarpmSat, 02 Mar 2013 16:40:22 +04002013-03-02T16:40:22+04:0004 2013, 16:40:22
0

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

Значение слов

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

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

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 страниц, содержащих слово «лиса», и ни одной страницы, содержащей «имбирь, лисица, любит фрукты», несмотря на то, что это совершенно правильное английское предложение, и мы все понимаем, что оно означает.

Состав

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

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

Дальнейшее чтение

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


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

ответил mbatchkarov 2 MarpmSat, 02 Mar 2013 15:15:56 +04002013-03-02T15:15:56+04:0003 2013, 15:15:56
0

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

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

  • qi - это вес tf-idf термина i в запросе.
  • di - это tf-idf
  • вес термина i в документе. | Д | и | д | длины д и д.
  • Это косинусное сходство q и d. , , , , , или же, эквивалентно, косинус угла между q и d.

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

ответил novice_dev 14 FebruaryEurope/MoscowbSat, 14 Feb 2015 01:56:14 +0300000000amSat, 14 Feb 2015 01:56:14 +030015 2015, 01:56:14
0

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

ответил TheSN 5 J000000Thursday18 2018, 08:44:39
0

Попробуй это. Загрузите файл 'numberbatch-en-17.06.txt' с https://conceptnet.s3.amazonaws.com/downloads/2017/numberbatch/numberbatch-en-17.06.txt.gz и распакуйте его. Функция 'get_sentence_vector' использует простую сумму векторов слов. Однако его можно улучшить, используя взвешенную сумму, где веса пропорциональны Tf-Idf каждого слова.

import math
import numpy as np

std_embeddings_index = {}
with open('path/to/numberbatch-en-17.06.txt') as f:
    for line in f:
        values = line.split(' ')
        word = values[0]
        embedding = np.asarray(values[1:], dtype='float32')
        std_embeddings_index[word] = embedding

def cosineValue(v1,v2):
    "compute cosine similarity of v1 to v2: (v1 dot v2)/{||v1||*||v2||)"
    sumxx, sumxy, sumyy = 0, 0, 0
    for i in range(len(v1)):
        x = v1[i]; y = v2[i]
        sumxx += x*x
        sumyy += y*y
        sumxy += x*y
    return sumxy/math.sqrt(sumxx*sumyy)


def get_sentence_vector(sentence, std_embeddings_index = std_embeddings_index ):
    sent_vector = 0
    for word in sentence.lower().split():
        if word not in std_embeddings_index :
            word_vector = np.array(np.random.uniform(-1.0, 1.0, 300))
            std_embeddings_index[word] = word_vector
        else:
            word_vector = std_embeddings_index[word]
        sent_vector = sent_vector + word_vector

    return sent_vector

def cosine_sim(sent1, sent2):
    return cosineValue(get_sentence_vector(sent1), get_sentence_vector(sent2))

Я побежал за заданными предложениями и нашел следующие результаты

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 ."

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

0.9851735249068168
0.6570885718962608
0.6589335425458225
ответил Manideep Karthik 21 32018vEurope/Moscow11bEurope/MoscowWed, 21 Nov 2018 10:42:36 +0300 2018, 10:42:36

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132