sklearn pairwise python python-3.x cosine-similarity

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)))