194 votes

Similitude en cosinus entre 2 listes de nombres

Je veux calculer le similarité cosinus entre deux listes disons par exemple la liste 1 qui est dataSetI et la liste 2 qui est dataSetII .

Disons que dataSetI es [3, 45, 7, 2] y dataSetII es [2, 54, 13, 15] . Les longueurs des listes sont toujours égal. Je veux rapporter la similarité du cosinus comme un nombre entre 0 et 1.

dataSetI = [3, 45, 7, 2]
dataSetII = [2, 54, 13, 15]

def cosine_similarity(list1, list2):
  # How to?
  pass

print(cosine_similarity(dataSetI, dataSetII))

246voto

Sam Points 585

Vous devriez essayer SciPy . Il possède un tas de routines scientifiques utiles, par exemple, "des routines pour le calcul numérique d'intégrales, la résolution d'équations différentielles, l'optimisation et les matrices éparses". Il utilise NumPy, optimisé et très rapide, pour le calcul des nombres. Voir aquí pour l'installation.

Notez que spatial.distance.cosine calcule le distance et non la similitude. Ainsi, vous devez soustraire la valeur de 1 pour obtenir la valeur de similarité .

from scipy import spatial

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

245voto

dontloo Points 2754

Une autre version basée sur numpy sólo

from numpy import dot
from numpy.linalg import norm

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

110voto

Akavall Points 7357

Vous pouvez utiliser cosine_similarity forme de fonction 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]])

44voto

Mike Housky Points 3194

Je suppose que les performances n'ont pas beaucoup d'importance ici, mais je ne peux pas résister. La fonction zip() recopie complètement les deux vecteurs (plutôt une transposition matricielle, en fait) juste pour obtenir les données dans l'ordre "Pythonique". Il serait intéressant de voir l'implémentation des rouages :

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

Cela permet d'extraire les éléments un par un, comme en C, mais ne fait pas de copie de tableau en masse et fait tout ce qui est important dans une seule boucle for, et utilise une seule racine carrée.

ETA : Mise à jour de l'appel print pour être une fonction. (L'original était Python 2.7, pas 3.3. La version actuelle fonctionne sous Python 2.7 avec un fichier from __future__ import print_function déclaration.) Le résultat est le même, dans les deux cas.

CPYthon 2.7.3 sur Core 2 Duo 3.0GHz :

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

Ainsi, la méthode non-pythonique est environ 3,6 fois plus rapide dans ce cas.

26voto

Mohammed Points 261

Sans utiliser d'importations

math.sqrt(x)

peut être remplacé par

x** .5

sans utiliser numpy.dot(), vous devez créer votre propre fonction point en utilisant la compréhension de liste :

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

et ensuite, il suffit d'appliquer la formule de similarité du cosinus :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X