Косинус сходства между 2-мя списками
Мне нужно вычислить сходство косинусов между двумя списками, скажем, например, список 1, который dataSetI
и список 2, который dataSetII
. Я не могу использовать ничего, например numpy или модуль статистики. Я должен использовать общие модули (математика и т.д.) (И, по мере возможности, наименьшие модули, чтобы сократить затраченное время).
Скажем, dataSetI
есть [3, 45, 7, 2]
, а dataSetII
- [2, 54, 13, 15]
. Длина списков всегда равна.
Конечно, сходство косинусов находится между 0 и 1, и для этого оно будет округлено до третьего или четвертого десятичного знака с помощью format(round(cosine, 3))
.
Благодарим вас за помощь.
Ответы
Ответ 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()