python: как рассчитать косинусное сходство двух списков слов?

Я хочу рассчитать косинусное сходство двух списков, например:

A = [u'home (private)', u'bank', u'bank', u'building(condo/apartment)','factory']

B = [u'home (private)', u'school', u'bank', u'shopping mall']

Я знаю, что косинусное сходство A и B должно быть

3/(sqrt(7)*sqrt(4)).

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

Знаете ли вы, как вычислить вхождение слова в этот сложный список, чтобы для списка B вхождение слова можно было представить как

{'home (private):1, 'school':1, 'bank': 1, 'shopping mall':1}? 

Или вы знаете, как вычислить косинусное сходство этих двух списков?

Большое тебе спасибо


person gladys0313    schedule 02.03.2015    source источник
comment
Как бы вы определили cosine similarity ? откуда взялись эти переменные 3/(sqrt(7)*sqrt(4)). ?   -  person ZdaR    schedule 03.03.2015
comment
Я просто знаю один способ определить косинусное сходство, которое представляет собой просто точку (A, B)/|A|.|B|, точно так же, как A = [2, 1, 1, 1, 0, 0] и B = [1 ,1,0,0,1,1], а их косинусное сходство равно 3/(sqrt(7)*sqrt(4))   -  person gladys0313    schedule 03.03.2015


Ответы (2)


Сначала создайте словарь (это технический термин для списка всех отдельных слов в наборе или корпусе).

vocab = {}
i = 0

# loop through each list, find distinct words and map them to a
# unique number starting at zero

for word in A:
    if word not in vocab:
        vocab[word] = i
        i += 1


for word in B:
    if word not in vocab:
        vocab[word] = i
        i += 1

Словарь vocab теперь сопоставляет каждому слову уникальный номер, начинающийся с нуля. Мы будем использовать эти числа в качестве индексов в массиве (или векторе).

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

import numpy as np

# create a numpy array (vector) for each input, filled with zeros
a = np.zeros(len(vocab))
b = np.zeros(len(vocab))

# loop through each input and create a corresponding vector for it
# this vector counts occurrences of each word in the dictionary

for word in A:
    index = vocab[word] # get index from dictionary
    a[index] += 1 # increment count for that index

for word in B:
    index = vocab[word]
    b[index] += 1

Последним шагом является фактическое вычисление косинусного подобия.

# use numpy's dot product to calculate the cosine similarity
sim = np.dot(a, b) / np.sqrt(np.dot(a, a) * np.dot(b, b))

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

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

  1. nltk
  2. gensim
  3. spaCy
person Waylon Flinn    schedule 03.11.2015

person    schedule
comment
Большое спасибо за ваш ответ. Это кажется очень крутым, но в словах = список (a_vals.keys () | b_vals.keys ()) интерпретатор говорит: «Ошибка типа: неподдерживаемый тип (ы) операнда для |: «список» и «список». Есть идеи? ' - person gladys0313; 03.03.2015
comment
Извините, я тестировал в Python 3.4. Для 2.x вы бы сделали word = list(set(a_vals) | set(b_vals)). - person Hugh Bothwell; 03.03.2015