python text - Вычислить подобие косинуса с учетом 2 строк предложения




similarity cosine (5)

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

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

Answers

Спасибо @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 - tf-idf
  • вес термина i в документе. | Д | и | d | - длины q и d.
  • Это сходство косинусов q и d. , , , , , или, что то же самое, косинус угла между q и d.

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


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


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

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

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

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

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


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

Здесь описывается формула косинуса, используемая here .

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

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


Вот более или менее ответ sampath, немного очищенный и представленный как функция:

String streamToString(InputStream in) throws IOException {
  StringBuilder out = new StringBuilder();
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  for(String line = br.readLine(); line != null; line = br.readLine()) 
    out.append(line);
  br.close();
  return out.toString();
}






python string nlp similarity cosine-similarity