pairwise - cosine similarity python text
Similitud coseno entre 2 listas de nĂºmeros (10)
Deberías probar SciPy . Tiene un montón de rutinas científicas útiles, por ejemplo, "rutinas para calcular integrales numéricamente, resolver ecuaciones diferenciales, optimización y matrices dispersas". Utiliza el NumPy súper rápido optimizado para su número de crujidos. Vea here para instalar.
Tenga en cuenta que spatial.distance.cosine calcula la distancia , y no la similitud. Por lo tanto, debe restar el valor de 1 para obtener la similitud .
from scipy import spatial
dataSetI = [3, 45, 7, 2]
dataSetII = [2, 54, 13, 15]
result = 1 - spatial.distance.cosine(dataSetI, dataSetII)
Necesito calcular la similitud del coseno entre dos listas , digamos por ejemplo la lista 1 que es dataSetI
y la lista 2 que es dataSetII
. No puedo usar nada como numpy o un módulo de estadísticas. Debo usar módulos comunes (matemática, etc.) (y los menos módulos posibles, para reducir el tiempo dedicado).
Digamos que dataSetI
es [3, 45, 7, 2]
y dataSetII
es [2, 54, 13, 15]
. La longitud de las listas es siempre igual.
Por supuesto, la similitud del coseno está entre 0 y 1 , y por el bien de ella, se redondeará al tercer o cuarto decimal con format(round(cosine, 3))
.
Muchas gracias de antemano por ayudar.
Hice un benchmark basado en varias respuestas en la pregunta y se cree que el siguiente fragmento es la mejor opción:
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)
El resultado me sorprende de que la implementación basada en scipy
no sea la más rápida. Hice un perfil y descubrí que el coseno en scipy toma mucho tiempo para lanzar un vector de la lista de python a numpy array.
No creo que el rendimiento sea importante aquí, pero no me puedo resistir. La función zip () copia completamente ambos vectores (más de una matriz transpuesta, en realidad) solo para obtener los datos en orden "Pythonic". Sería interesante cronometrar la implementación de tuercas y pernos:
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
Eso pasa por el ruido tipo C de los elementos de extracción uno a la vez, pero no hace una copia masiva de arreglos y hace que todo lo importante se haga en un solo ciclo, y usa una sola raíz cuadrada.
ETA: Llamada de impresión actualizada para ser una función. (El original era Python 2.7, no 3.3. El actual se ejecuta bajo Python 2.7 con una from __future__ import print_function
.) El resultado es el mismo, de cualquier manera.
CPYthon 2.7.3 en 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
Entonces, la forma antiponética es aproximadamente 3.6 veces más rápida en este caso.
Puede usar esta función simple para calcular la similitud del coseno:
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])))
Puede usar la función 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]])
Puedes hacer esto en Python usando una función simple:
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)
Usando numpy compare una lista de números a múltiples listas (matriz):
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]
otra versión basada solo en numpy
from numpy import dot
from numpy.linalg import norm
cos_sim = dot(a, b)/(norm(a)*norm(b))
sin usar ninguna importación
math.sqrt (x)
puede ser reemplazado por
x ** .5
sin usar numpy.dot () debe crear su propia función de punto usando la lista de comprensión:
def dot(A,B):
return (sum(a*b for a,b in zip(A,B)))
y luego es solo una simple cuestión de aplicar la fórmula de similitud del coseno:
def cosine_similarity(a,b):
return dot(a,b) / ( (dot(a,a) **.5) * (dot(b,b) ** .5) )
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)
Puede redondearlo después de la computación:
cosine = format(round(cosine_measure(v1, v2), 3))
Si lo quieres realmente corto, puedes usar este delineador:
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)))