Подтвердить что ты не робот

Косинус сходства между 2-мя списками

Мне нужно вычислить сходство косинусов между двумя списками, скажем, например, список 1, который dataSetI и список 2, который dataSetII. Я не могу использовать ничего, например numpy или модуль статистики. Я должен использовать общие модули (математика и т.д.) (И, по мере возможности, наименьшие модули, чтобы сократить затраченное время).

Скажем, dataSetI есть [3, 45, 7, 2], а dataSetII - [2, 54, 13, 15]. Длина списков всегда равна.

Конечно, сходство косинусов находится между 0 и 1, и для этого оно будет округлено до третьего или четвертого десятичного знака с помощью format(round(cosine, 3)).

Благодарим вас за помощь.

4b9b3361

Ответ 1

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

Обратите внимание, что в пространстве .distance.cosine вычисляется расстояние, а не сходство. Итак, вы должны вычесть значение из 1, чтобы получить сходство.

from scipy import spatial

dataSetI = [3, 45, 7, 2]
dataSetII = [2, 54, 13, 15]
result = 1 - spatial.distance.cosine(dataSetI, dataSetII)

Ответ 2

другая версия, основанная только на numpy

from numpy import dot
from numpy.linalg import norm

cos_sim = dot(a, b)/(norm(a)*norm(b))

Ответ 3

Вы можете использовать функцию cosine_similarity из формы sklearn.metrics.pairwise docs

In [23]: from sklearn.metrics.pairwise import cosine_similarity

In [24]: cosine_similarity([[1, 0, -1]], [[-1,-1, 0]])
Out[24]: array([[-0.5]])

Ответ 4

Я не думаю, что производительность здесь очень важна, но я не могу сопротивляться. Функция zip() полностью восстанавливает оба вектора (скорее всего, транспонирование матрицы), чтобы получить данные в "Pythonic" порядке. Было бы интересно время выполнения гаек и болтов:

import math
def cosine_similarity(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)

v1,v2 = [3, 45, 7, 2], [2, 54, 13, 15]
print(v1, v2, cosine_similarity(v1,v2))

Output: [3, 45, 7, 2] [2, 54, 13, 15] 0.972284251712

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

ETA: Обновленный вызов печати является функцией. (Исходным был Python 2.7, а не 3.3. Ток работает под Python 2.7 с инструкцией from __future__ import print_function.) Результат тот же, в любом случае.

CPYthon 2.7.3 на 3.0GHz Core 2 Duo:

>>> timeit.timeit("cosine_similarity(v1,v2)",setup="from __main__ import cosine_similarity, v1, v2")
2.4261788514654654
>>> timeit.timeit("cosine_measure(v1,v2)",setup="from __main__ import cosine_measure, v1, v2")
8.794677709375264

Таким образом, непитонический способ в этом случае примерно в 3,6 раза быстрее.

Ответ 5

Я сделал тест, основанный на нескольких ответах на вопрос, и следующий фрагмент считается лучшим выбором:

def dot_product2(v1, v2):
    return sum(map(operator.mul, v1, v2))


def vector_cos5(v1, v2):
    prod = dot_product2(v1, v2)
    len1 = math.sqrt(dot_product2(v1, v1))
    len2 = math.sqrt(dot_product2(v2, v2))
    return prod / (len1 * len2)

Результат меня удивляет, что реализация на основе scipy не самая быстрая. Я профилировал и обнаружил, что косинус в scipy занимает много времени, чтобы привести вектор из списка python к массиву numpy.

enter image description here

Ответ 6

import math
from itertools import izip

def dot_product(v1, v2):
    return sum(map(lambda x: x[0] * x[1], izip(v1, v2)))

def cosine_measure(v1, v2):
    prod = dot_product(v1, v2)
    len1 = math.sqrt(dot_product(v1, v1))
    len2 = math.sqrt(dot_product(v2, v2))
    return prod / (len1 * len2)

Вы можете округлить его после вычисления:

cosine = format(round(cosine_measure(v1, v2), 3))

Если вы хотите, чтобы он был очень коротким, вы можете использовать этот однострочный шрифт:

from math import sqrt
from itertools import izip

def cosine_measure(v1, v2):
    return (lambda (x, y, z): x / sqrt(y * z))(reduce(lambda x, y: (x[0] + y[0] * y[1], x[1] + y[0]**2, x[2] + y[1]**2), izip(v1, v2), (0, 0, 0)))

Ответ 7

без использования импорта

math.sqrt(x)

можно заменить на

x**.5

без использования numpy.dot() вы должны создать свою собственную функцию точек, используя понимание списка:

def dot(A,B): 
    return (sum(a*b for a,b in zip(A,B)))

и тогда это просто вопрос применения формулы косинуса подобия:

def cosine_similarity(a,b):
    return dot(a,b) / ( (dot(a,a) **.5) * (dot(b,b) ** .5) )

Ответ 8

Вы можете сделать это в Python, используя простую функцию:

def get_cosine(text1, text2):
  vec1 = text1
  vec2 = text2
  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 round(float(numerator) / denominator, 3)
dataSet1 = [3, 45, 7, 2]
dataSet2 = [2, 54, 13, 15]
get_cosine(dataSet1, dataSet2)

Ответ 9

Используя numpy, сравните один список чисел с несколькими списками (матрицей):

def cosine_similarity(vector,matrix):
   return ( np.sum(vector*matrix,axis=1) / ( np.sqrt(np.sum(matrix**2,axis=1)) * np.sqrt(np.sum(vector**2)) ) )[::-1]

Ответ 10

Вы можете использовать эту простую функцию для вычисления сходства косинусов:

def cosine_similarity(a, b):
return sum([i*j for i,j in zip(a, b)])/(math.sqrt(sum([i*i for i in a]))* math.sqrt(sum([i*i for i in b])))

Ответ 11

Если вы уже используете PyTorch, вам следует воспользоваться их реализацией CosineSimility.

Предположим, у вас есть два n -dimensional numpy.ndarray s, v1 и v2, то есть их форма (n,). Вот как вы получаете их косинусное сходство:

import torch
import torch.nn as nn

cos = nn.CosineSimilarity()
cos(torch.tensor([v1]), torch.tensor([v2])).item()

Или предположим, у вас есть два numpy.ndarray w1 и w2, чьи формы обе (m, n). Ниже приведен список сходств косинусов, каждое из которых является сходством косинусов между строкой в w1 и соответствующей строкой в w2:

cos(torch.tensor(w1), torch.tensor(w2)).tolist()